Interview frequency: …
Short answer
It manages complex state with multiple transitions or updates that depend on scattered steps, moving state-change logic into a separate pure Reducer function.
Explanation
useReducer follows the Redux pattern: it accepts a reducer of (state, action) => newState and an initial state, then returns [state, dispatch]. Use it when state is a complex object with nested fields, update logic should be tested separately from the component, or a stable dispatch function can replace many callbacks.
Code example
type Action = { type: 'inc' } | { type: 'dec' } | { type: 'reset' };
function reducer(state: number, action: Action): number {
switch (action.type) {
case 'inc': return state + 1;
case 'dec': return state - 1;
case 'reset': return 0;
default: return state;
}
}
function Counter() {
const [count, dispatch] = useReducer(reducer, 0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'inc' })}>+</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</div>
);
}Common mistakes
- Performing side effects (such as API calls) directly inside the reducer instead of keeping it 100% pure.