useReducer vs useState
What useReducer does
useReducer is a React hook that lets you manage state through a reducer function.
It resembles the Redux principle:
state is not changed directly, but through an "action".
Syntax
javascript
const [state, dispatch] = useReducer(reducer, initialState);state- the current statedispatch- the function that sends an "action"reducer(state, action)- the function that receives the current state and the "action",
and returns the new state
Simple example
javascript
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}How this works:
- On click, React calls
dispatch({ type: "increment" }). - React calls
reducer(state, action). - The reducer returns the new state → React re-renders the component.
How useReducer differs from useState
| Criterion | useState | useReducer |
|---|---|---|
| State type | Simple (single value) | Complex (object, array, update logic) |
| Update | setState(newValue) | dispatch({ type, payload }) |
| Update logic | Directly in the component | Extracted into a separate function (reducer) |
| When to use | Simple cases (counter, form, toggle) | When the state is complex or driven by different actions |
| Good fit for | Small components | Large / complex states |
| Similar to | A built-in Redux alternative | A mini-Redux inside one component |
Comparison example
The useState version
javascript
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);Simple, but does not scale if the logic gets complex.
The useReducer version
javascript
function reducer(state, action) {
switch (action.type) {
case "increment":
return { ...state, count: state.count + 1 };
case "decrement":
return { ...state, count: state.count - 1 };
case "reset":
return { ...state, count: 0 };
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });Now you can manage the logic centrally -
handy when there are many branches or states.
When it is better to use useReducer
Use useReducer when:
- The state is complex (for example, an object with several fields).
- The update logic depends on different action types.
- Several parts of the code may update the same state.
- You want to separate the logic (reducer) from the UI component.
Examples:
- A form with validation
- A multi-step process (wizard / onboarding)
- A list of items with filtering, sorting, adding, and removing
A "form" example with useReducer
javascript
function formReducer(state, action) {
switch (action.type) {
case "changeField":
return { ...state, [action.field]: action.value };
case "reset":
return { name: "", email: "" };
default:
return state;
}
}
function Form() {
const [form, dispatch] = useReducer(formReducer, { name: "", email: "" });
return (
<form>
<input
value={form.name}
onChange={(e) =>
dispatch({ type: "changeField", field: "name", value: e.target.value })
}
/>
<input
value={form.email}
onChange={(e) =>
dispatch({ type: "changeField", field: "email", value: e.target.value })
}
/>
<button onClick={() => dispatch({ type: "reset" })}>Clear</button>
</form>
);
}Now it is easy to extend the form - just add a new case.
Summary
| Question | Answer |
|---|---|
What does useReducer do? | Manages state through a reducer function, reacting to "actions" |
How does it differ from useState? | useState just stores a value, useReducer manages complex logic |
| When to use it? | For complex or related updates |
| When not to? | For simple numbers, strings, flags - useState is simpler |
| How is it similar to Redux? | The same "action → reducer → new state" principle, just local |
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.