0Pricing
Frontend Academy · Aula

useReducer para estado complexo

Modele transições de estado com uma função reducer, despache objetos de ação e prefira useReducer a useState quando a lógica de estado ficar complexa.

useReducer para estado complexo é uma aula grátis de Frontend Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Frontend Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Frontend Academy inclui 4 aulas no total.

Quando useState não é suficiente

Quando as transições de estado envolvem lógica complexa, vários valores relacionados ou condições nas quais o novo estado depende do estado anterior de maneiras não triviais, useReducer é uma opção mais organizada do que várias chamadas de useState.

Padrão de função redutora

Um redutor é uma função pura: (state, action) => newState. Ele recebe o estado atual e um objeto de ação e retorna o próximo estado. Sem mutações — sempre retorne um objeto novo.

type Action =
  | { type: 'increment' }
  | { type: 'decrement' }
  | { type: 'reset'; payload: number };

function counterReducer(state: number, action: Action): number {
  switch (action.type) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset':     return action.payload;
    default: return state;
  }
}

Sintaxe de useReducer

useReducer(reducer, initialState) retorna o estado atual e uma função dispatch. Chame dispatch com um objeto de ação para iniciar uma transição de estado.

function Counter() {
  const [count, dispatch] = useReducer(counterReducer, 0);

  return (
    <div>
      <p>{count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </div>
  );
}

Ações tipadas — uniões discriminadas

Use tipos de união discriminada do TypeScript para as ações e obtenha verificação exaustiva de tipos na estrutura de seleção do redutor.

type CartAction =
  | { type: 'ADD_ITEM'; item: CartItem }
  | { type: 'REMOVE_ITEM'; id: string }
  | { type: 'SET_QUANTITY'; id: string; qty: number }
  | { type: 'CLEAR' };

Exemplo de estado complexo: carrinho de compras

Um carrinho de compras com operações de adição, remoção e atualização de quantidade é um caso de uso perfeito para useReducer.

interface CartState {
  items: CartItem[];
  total: number;
}

function cartReducer(state: CartState, action: CartAction): CartState {
  switch (action.type) {
    case 'ADD_ITEM': {
      const exists = state.items.find(i => i.id === action.item.id);
      if (exists) {
        const items = state.items.map(i =>
          i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i
        );
        return { ...state, items, total: calcTotal(items) };
      }
      const items = [...state.items, { ...action.item, qty: 1 }];
      return { ...state, items, total: calcTotal(items) };
    }
    case 'CLEAR': return { items: [], total: 0 };
    default: return state;
  }
}

dispatch é estável

A função dispatch é estável — ela não muda entre renderizações. É seguro passá-la como uma propriedade ou usá-la como uma dependência de useEffect sem provocar novas execuções.

Combinando useReducer + useContext

Um padrão poderoso: um contexto fornece tanto o estado quanto a função de despacho, permitindo que qualquer consumidor leia o estado ou envie ações sem passagem de propriedades em cadeia.

const CartContext = createContext<{ state: CartState; dispatch: Dispatch<CartAction> } | null>(null);

function CartProvider({ children }: { children: React.ReactNode }) {
  const [state, dispatch] = useReducer(cartReducer, { items: [], total: 0 });
  return <CartContext.Provider value={{ state, dispatch }}>{children}</CartContext.Provider>;
}

useReducer versus useState

Escolha useReducer quando: o estado tiver vários subvalores, o próximo estado depender do anterior de maneiras complexas, houver muitas transições nomeadas explicitamente ou você quiser testar a lógica do estado separadamente do componente.

Testando redutores isoladamente

Como os redutores são funções puras, é trivial testá-los sem renderizar nenhum componente.

test('increment action increases count', () => {
  expect(counterReducer(0, { type: 'increment' })).toBe(1);
  expect(counterReducer(5, { type: 'increment' })).toBe(6);
});

test('reset action sets count to payload', () => {
  expect(counterReducer(42, { type: 'reset', payload: 0 })).toBe(0);
});

Immer para atualizações imutáveis

A biblioteca immer permite escrever código que parece mutável, mas produz um estado imutável novo. É útil para atualizações complexas de objetos aninhados em redutores.

Verificação rápida

Qual é a assinatura de função de um redutor?

Recapitulação: useReducer

(estado, ação) => newState — puro, sem mutações. useReducer(redutor, inicial) retorna [estado, despacho]. Use tipos de ação de união discriminada para maior segurança. O despacho é estável. Excelente para estados complexos com muitas transições. Combine com useContext para gerenciamento de estado global. Teste os redutores independentemente como funções puras.

Perguntas Frequentes

A aula “useReducer para estado complexo” é grátis?

Sim — o texto completo de “useReducer para estado complexo” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Frontend Academy, atualize para CoddyKit PRO. O curso de Frontend Academy inclui 4 aulas no total.

O que vou aprender em “useReducer para estado complexo”?

Modele transições de estado com uma função reducer, despache objetos de ação e prefira useReducer a useState quando a lógica de estado ficar complexa. Você pratica Frontend Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Frontend Academy?

Nenhuma experiência prévia é necessária. Frontend Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “useReducer para estado complexo”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Frontend Academy?

Sim. Cada aula de Frontend Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. useContext para estado global
  2. useReducer para estado complexo
  3. useMemo e useCallback para desempenho
  4. Hooks personalizados: extraindo lógica reutilizável
← Voltar para Frontend Academy