> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-pt/guias-do-contribuidor/padroes-de-ui/store-setup.md).

# Configuração da Store

Esta página cobre como configurar sua store Redux, configurar hooks tipados e organizar a estrutura do projeto.

## Estrutura de Pastas

Os projetos DEVEM seguir esta estrutura para consistência e manutenibilidade:

```
src/
  app/
    store.ts              # Configuração da store
    hooks.ts              # Hooks tipados (useAppDispatch/useAppSelector)
  shared/
    types/                # DTOs (API), modelos de domínio, mappers
    utils/                # Utilitários compartilhados
  services/
    client.ts             # Cliente base do RTK Query
    baseQuery.ts          # Query base com auth/chainId/retry
  features/
    user/
      user.client.ts      # Endpoints do RTK Query
      user.slice.ts       # Slice de estado de UI
      user.selectors.ts   # Selectors memoizados
      __tests__/          # Testes
    land/
      land.client.ts
      land.slice.ts
      land.selectors.ts
    credits/
      credits.client.ts
      credits.slice.ts
      credits.selectors.ts
```

### Princípios de Organização de Pastas

* **Baseado em feature** - Agrupar por domínio de negócio, não por papel técnico
* **Co-localização** - Manter o código relacionado junto
* **Separação clara** - Distinguir entre dados remotos (`.client.ts`) e estado local (`.slice.ts`)

## Configuração da Store

A store DEVE ser configurada com o `configureStore` do RTK e incluir todo o middleware necessário.

### Configuração Básica da Store

```tsx
// src/app/store.ts
import { configureStore } from '@reduxjs/toolkit';
import { client } from '@/services/client';
import userReducer from '@/features/user/user.slice';
import landReducer from '@/features/land/land.slice';
import creditsReducer from '@/features/credits/credits.slice';

export const store = configureStore({
  reducer: {
    // Reducer do cliente RTK Query (DEVE ser incluído)
    [client.reducerPath]: client.reducer,
    
    // Feature slices
    user: userReducer,
    land: landReducer,
    credits: creditsReducer,
  },
  
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        // Ignorar redux-persist ou outros caminhos conhecidos não serializáveis
        ignoredActions: ['persist/PERSIST', 'persist/REHYDRATE'],
        ignoredPaths: ['register'],
      },
    }).concat(client.middleware), // DEVE incluir o middleware do RTK Query
    
  devTools: process.env.NODE_ENV !== 'production',
});

// Exportar tipos para uso em toda a app
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
```

### Opções de Configuração

#### Verificação de Serializabilidade

O `serializableCheck` o middleware valida que todo o estado é serializável. Configure-o para ignorar exceções conhecidas:

```tsx
serializableCheck: {
  // Ações para ignorar
  ignoredActions: [
    'persist/PERSIST',
    'persist/REHYDRATE',
  ],
  // Caminhos de estado para ignorar
  ignoredPaths: ['register', 'socket.connection'],
}
```

{% hint style="warning" %}
**Nunca desative `serializableCheck` completamente.** Em vez disso, configure exceções e mantenha dados não serializáveis fora do Redux.
{% endhint %}

#### Dev Tools

Habilite o Redux DevTools em desenvolvimento para depuração:

```tsx
devTools: process.env.NODE_ENV !== 'production'
```

Para depuração em produção (se necessário), use configuração específica:

```tsx
devTools: process.env.NODE_ENV !== 'production' ? true : {
  name: 'Decentraland App',
  trace: false,
  traceLimit: 25,
}
```

## Hooks Tipados

Crie versões tipadas de `useDispatch` e `useSelector` para melhor inferência de tipos e experiência do desenvolvedor.

### Configuração dos Hooks

```tsx
// src/app/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from './store';

// Hook de dispatch tipado
export const useAppDispatch = () => useDispatch<AppDispatch>();

// Hook de selector tipado
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
```

### Uso em Componentes

```tsx
// ❌ Ruim: Usando hooks padrão
import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '@/app/store';

function Component() {
  const dispatch = useDispatch(); // Sem inferência de tipos
  const user = useSelector((state: RootState) => state.user); // Tipagem manual
}

// ✅ Bom: Usando hooks tipados
import { useAppDispatch, useAppSelector } from '@/app/hooks';

function Component() {
  const dispatch = useAppDispatch(); // Tipado automaticamente
  const user = useAppSelector((state) => state.user); // RootState inferido
}
```

### Benefícios dos Hooks Tipados

1. **Autocomplete** - IntelliSense completo para o formato do estado
2. **Segurança de Tipos** - Capturar erros em tempo de compilação
3. **Refatoração** - Renomear propriedades do estado com confiança
4. **Menos Boilerplate** - Não há necessidade de especificar `RootState` repetidamente

## Configuração do Provider

Envuelva sua app com o Provider do Redux:

### Next.js App Router

```tsx
// app/providers.tsx
'use client';

import { Provider } from 'react-redux';
import { store } from '@/app/store';

export function Providers({ children }: { children: React.ReactNode }) {
  return <Provider store={store}>{children}</Provider>;
}
```

```tsx
// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

### Next.js Pages Router

```tsx
// pages/_app.tsx
import { Provider } from 'react-redux';
import { store } from '@/app/store';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  );
}
```

### React (Vite/CRA)

```tsx
// main.tsx / index.tsx
import { Provider } from 'react-redux';
import { store } from '@/app/store';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
```

## Configuração de Ambiente

Configure configurações específicas por ambiente:

```tsx
// src/config/constants.ts
export const API_URL = process.env.NEXT_PUBLIC_API_URL || 'https://api.decentraland.org';
export const WS_URL = process.env.NEXT_PUBLIC_WS_URL || 'wss://api.decentraland.org';
export const CHAIN_ID = process.env.NEXT_PUBLIC_CHAIN_ID || '1';

// Configurações do RTK Query
export const RTK_QUERY_CONFIG = {
  keepUnusedDataFor: 60, // segundos
  refetchOnFocus: true,
  refetchOnReconnect: true,
  refetchOnMountOrArgChange: 30, // segundos
} as const;
```

## Definições de Tipos

Crie definições de tipos compartilhadas para consistência:

```tsx
// src/shared/types/api.types.ts
/** Wrapper de resposta da API */
export interface ApiResponse<T> {
  ok: boolean;
  data: T;
  error?: string;
}

/** Resposta paginada */
export interface PaginatedResponse<T> {
  items: T[];
  total: number;
  page: number;
  limit: number;
}

/** Erro comum da API */
export interface ApiError {
  message: string;
  code: string;
  details?: Record<string, any>;
}
```

```tsx
// src/shared/types/domain.types.ts
/** Modelo de domínio User */
export interface User {
  id: string;
  address: string;
  name?: string;
  avatar?: string;
  createdAt: string;
}

/** Modelo de domínio Parcel */
export interface Parcel {
  id: string;
  x: number;
  y: number;
  owner: string;
  name?: string;
}
```

## Múltiplas Instâncias da Store

Para testes ou micro-frontends, você pode precisar de múltiplas instâncias da store:

```tsx
// src/app/store.ts
import { configureStore } from '@reduxjs/toolkit';

export function createStore(preloadedState?: Partial<RootState>) {
  return configureStore({
    reducer: {
      // ... reducers
    },
    preloadedState,
    // ... outra configuração
  });
}

// Instância padrão da store
export const store = createStore();

export type AppStore = ReturnType<typeof createStore>;
export type RootState = ReturnType<AppStore['getState']>;
export type AppDispatch = AppStore['dispatch'];
```

## Boas Práticas

### 1. Store Única

Use sempre uma única instância da store por aplicação:

```tsx
// ✅ Bom: Uma store
export const store = configureStore({ ... });

// ❌ Ruim: Múltiplas stores
export const userStore = configureStore({ ... });
export const cartStore = configureStore({ ... });
```

### 2. Carregamento Lento de Reducers

Para code splitting, injete reducers dinamicamente:

```tsx
import { combineReducers } from '@reduxjs/toolkit';

const staticReducers = {
  user: userReducer,
};

export function createReducer(asyncReducers = {}) {
  return combineReducers({
    ...staticReducers,
    ...asyncReducers,
  });
}

// Na store
let currentReducers = createReducer();

export function injectReducer(key: string, reducer: Reducer) {
  currentReducers = createReducer({ [key]: reducer });
  store.replaceReducer(currentReducers);
}
```

### 3. Hot Module Replacement

Habilite HMR para reducers em desenvolvimento:

```tsx
if (process.env.NODE_ENV === 'development' && module.hot) {
  module.hot.accept('./reducer', () => {
    const newRootReducer = require('./reducer').default;
    store.replaceReducer(newRootReducer);
  });
}
```

### 4. Persistência de Estado

Ao usar redux-persist, configure com cuidado:

```tsx
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';

const persistConfig = {
  key: 'root',
  storage,
  // Persistir apenas slices específicos
  whitelist: ['user', 'preferences'],
  // Nunca persistir o cache do RTK Query
  blacklist: ['client'],
};

const persistedReducer = persistReducer(persistConfig, rootReducer);
```

## Próximos Passos

* Aprenda sobre [RTK Query](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-ui/rtk-query.md) para busca de dados
* Entender [Gerenciamento de Estado](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-ui/state-management.md) para estado local
* Rever [Padrões de Componentes](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-ui/component-patterns.md) para exemplos de uso


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/contributor/contributor-pt/guias-do-contribuidor/padroes-de-ui/store-setup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
