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
- useContext para estado global
- useReducer para estado complexo
- useMemo e useCallback para desempenho
- Hooks personalizados: extraindo lógica reutilizável