One of the most common questions developers ask when working with React Hooks is:
Should I use useState or useReducer?
Both hooks are used to manage state in functional components, but they serve different purposes based on complexity, structure, and how you plan to update the state.
Let’s break it down with real-world examples and when to use each.
âš¡ useState — Simple and Straightforward
useState is the most commonly used hook for handling local state.
✅ Best For
- Simple states like strings, numbers, and booleans
- Independent values (not tightly related)
- Quick reads and updates
📦 Example
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
Here, count is just a number — easy to update with setCount.
🧠useReducer — For Complex or Structured State
useReducer is perfect when your state is complex, deeply nested, or when multiple actions affect it. It’s similar to how reducers work in Redux.
✅ Best For
- Managing related pieces of state
- Handling multiple actions
- Complex state logic (e.g., form validation, state transitions)
📦 Example
import React, { useReducer } from 'react';
const initialState = { count: 0 };
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, initialState);
return (
<>
<h2>Count: {state.count}</h2>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
Instead of calling a setter, you dispatch an action and let the reducer decide what to do.
🆚 useState vs useReducer: Head-to-Head Comparison
| Feature |
useState |
useReducer |
| Syntax |
Simple, direct updates |
Structured, via reducer |
| State Complexity |
Low |
Medium to High |
| Multiple Values |
Separate useState calls |
Single reducer with one state object |
| Best For |
UI toggles, counters, inputs |
Forms, workflows, multi-step states |
| Code Maintainability |
Easy for small components |
Better for growing logic |
| Performance Optimization |
Basic |
Supports advanced patterns |
🚦 When Should You Use useReducer Instead of useState?
Use useReducer if
- You have multiple related states (e.g. name, email, password).
- You want to use actions and switch cases for updates.
- You’re doing complex state transitions (e.g.,
OPEN, LOADING, SUCCESS, ERROR).
- You plan to scale or refactor the state logic later.
Otherwise, stick with useState for quick and simple state handling.
🧩 Bonus Tip: You Can Combine Both!
Sometimes, using both makes sense. Use useReducer for the heavy lifting and useState for UI toggles or temporary flags.
✅ Conclusion
To summarize
- 🧵 Use
useState for a simple, isolated state.
- 🧶 Use
useReducer for a complex, related state with multiple transitions.
💡 Think of useState like a notepad — quick and handy.
Think of useReducer like a spreadsheet — organized and scalable.