useReducer
The useState alternative for complex state logic. When your state has multiple sub-values or the next state depends on the previous one in non-trivial ways, useReducer keeps things predictable.
01 — What it is
When you have multiple pieces of state that change together, or state transitions that follow strict rules, managing it with several useState calls gets messy. useReducer centralises all state logic into a single pure function — the reducer.
const [state, dispatch] = useReducer(reducer, initialState);
// reducer → (state, action) => newState
// initialState → the starting value
// state → current state
// dispatch → send an action to the reducer02 — How to use it
interface State {
count: number;
showText: boolean;
}
type Action =
| { type: "INCREMENT" }
| { type: "toggleShowText" };
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "toggleShowText":
return { ...state, showText: !state.showText };
default:
return state;
}
};You never call the reducer directly — you dispatch an action object and React calls the reducer for you. Multiple dispatches in one handler are batched into a single re-render.
// Dispatch a single action
dispatch({ type: "INCREMENT" });
// Dispatch multiple — React batches them
dispatch({ type: "INCREMENT" });
dispatch({ type: "toggleShowText" });03 — Live demo
One button dispatches two actions — an increment and a text toggle. Both are batched into a single re-render.
This text toggles with every click — dispatched alongside the increment.
04 — useState vs useReducer
| Situation | Use |
|---|---|
| Simple independent values | useState |
| Multiple values that change together | useReducer |
| Next state depends on previous | useReducer |
| State transitions follow strict rules | useReducer |
| Logic needs to be testable in isolation | useReducer |