Quando usar useReducer em vez de useState?
useState é perfeito para valores simples e independentes. Mas quando o
estado é complexo (vários campos relacionados) ou as atualizações seguem
transições claras (várias formas distintas de alterá-lo), espalhar a
lógica por muitos setX se torna frágil e difícil de acompanhar.
useReducer concentra toda essa lógica em uma única função: o reducer.
O reducer: (state, action) => nextState
Um reducer é uma função pura que recebe o estado atual e uma ação, e retorna o próximo estado. Ele não muta o estado: constrói e retorna um novo.
function reducer(state, action) {
switch (action.type) {
case "incrementar":
return { contagem: state.contagem + 1 };
case "decrementar":
return { contagem: state.contagem - 1 };
default:
return state;
}
}
dispatch: enviar ações
No componente, useReducer(reducer, estadoInicial) retorna um par:
o estado atual e uma função chamada dispatch. Para alterar o estado,
você "despacha" uma ação descrevendo o que aconteceu:
function Contador() {
const [state, dispatch] = useReducer(reducer, { contagem: 0 });
return (
<div>
<p>Contagem: {state.contagem}</p>
<button onClick={() => dispatch({ type: "incrementar" })}>+1</button>
<button onClick={() => dispatch({ type: "decrementar" })}>-1</button>
</div>
);
}
A ação costuma ser um objeto com uma propriedade type (e, se necessário, dados
extras como payload). A vantagem: a lógica vive em um único lugar, é fácil
de ler e de testar, e os componentes apenas dizem o que aconteceu, não como o
estado muda.
Nos exercícios,
useReducerjá está disponível: use-o diretamente, sem importá-lo.