Why Using One Object with
At some point, I started questioning useReducer.
If the goal is to manage multiple related states, couldn’t I just do this?
const [state, setState] = useState({
step: 1,
form: { name: "", email: "", password: "" },
errors: {},
isSubmitting: false,
isSuccess: false
})Everything is already grouped.
No scattered state. No multiple hooks.
So the question becomes:
Why would I still need <code>useReducer</code>?
The Part That Looks Equivalent
At first glance, this approach seems to solve the same problem.
Instead of:
- multiple <code>useState</code>
- multiple setters
You now have:
- one state object
- one <code>setState</code>
Cleaner structure. Less repetition.
It feels like:
problem solved
Where It Starts to Feel Off
The difference doesn’t show up in the shape of the state.
It shows up in the logic.
Updates start to look like this:
setState(prev => ({
...prev,
isSubmitting: false,
isSuccess: true
}))And elsewhere:
setState(prev => ({
...prev,
isSubmitting: false,
errors: { submit: "Failed" }
}))Individually, these are fine.
But over time:
- similar logic gets repeated
- related fields are updated in multiple places
- it becomes easier to forget something
The Missing Structure
The real issue isn’t how the data is stored.
It’s how the data changes.
With this approach, every update is:
“manually construct the next state”
There’s no shared definition of:
- what actions exist
- how state should transition
What useReducer Changes
useReducer introduces a constraint:
all state changes must go through a single function
Instead of writing updates everywhere:
dispatch({ type: "SUBMIT_SUCCESS" })
dispatch({ type: "SUBMIT_ERROR", payload: error })And handling them in one place:
case "SUBMIT_SUCCESS":
return {
...state,
isSubmitting: false,
isSuccess: true
}The Real Difference
It’s not about how many states you have.
It’s about where the logic lives.
With one-object useState
- state is centralized
- logic is scattered
With useReducer
- state is centralized
- logic is also centralized
Why This Matters
As the app grows:
- more actions appear
- more conditions are added
- more fields are updated together
Without structure, updates become:
harder to track, easier to break
With a reducer, you get:
- explicit transitions
- predictable behavior
- a single place to understand the system
The Shift in Thinking
At first, it feels like:
“I just need to organize my state”
But the real problem is:
“I need to organize how state changes”
Final Takeaway
Using one object with useState solves the shape of your data.
But it doesn’t solve the shape of your logic.
And that’s the gap useReducer fills.
Not by adding more complexity—
but by forcing your state transitions to live in one place, where they’re easier to see, reason about, and maintain.