¿Cuándo useReducer en lugar de useState?
useState es perfecto para valores simples e independientes. Pero cuando el
estado es complejo (varios campos relacionados) o las actualizaciones siguen
transiciones claras (varias formas distintas de cambiarlo), repartir la
lógica entre muchos setX se vuelve frágil y difícil de seguir.
useReducer concentra toda esa lógica en una sola función: el reducer.
El reducer: (state, action) => nextState
Un reducer es una función pura que recibe el estado actual y una acción, y devuelve el siguiente estado. No muta el estado: construye y devuelve uno nuevo.
function reducer(state, action) {
switch (action.type) {
case "incrementar":
return { cuenta: state.cuenta + 1 };
case "decrementar":
return { cuenta: state.cuenta - 1 };
default:
return state;
}
}
dispatch: enviar acciones
En el componente, useReducer(reducer, estadoInicial) devuelve un par:
el estado actual y una función dispatch. Para cambiar el estado,
"despachas" una acción describiendo qué ha pasado:
function Contador() {
const [state, dispatch] = useReducer(reducer, { cuenta: 0 });
return (
<div>
<p>Cuenta: {state.cuenta}</p>
<button onClick={() => dispatch({ type: "incrementar" })}>+1</button>
<button onClick={() => dispatch({ type: "decrementar" })}>-1</button>
</div>
);
}
La acción suele ser un objeto con una propiedad type (y, si hace falta, datos
extra como payload). La ventaja: la lógica vive en un solo sitio, es fácil
de leer y de probar, y los componentes solo dicen qué ocurrió, no cómo cambia
el estado.
En los ejercicios,
useReducerya está disponible: úsalo directamente, sin importarlo.