# Store Setup

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](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/ui-standards/rtk-query) para busca de dados
* Entender [Gerenciamento de Estado](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/ui-standards/state-management) para estado local
* Rever [Padrões de Componentes](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/ui-standards/component-patterns) para exemplos de uso
