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, 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 simple, isolated state.
-
🧶 Use useReducer
for complex, related state with multiple transitions.
💡 Think of useState
like a notepad — quick and handy.
Think of useReducer
like a spreadsheet — organized and scalable.