React community is vast and growing rapidly. For the same business case, there are different ways to solve a problem.
And, whenever there are multiple solutions to do the same thing, the question arises - “When to use one over the other?”
The answer most of the time is - It depends on the use case.
One such most-asked question while handling states is -
When to use useReducer over useState hook?
Let’s understand these hooks in detail and discuss which one should be preferred and when.
The useState hook
useState is a hook that allows us to have state variables in functional components.
It takes the initial state as an argument
and returns an array of two entries
- State value
- A function to update the state
The useReducer hook
The useReducer(reducer, initialState) hook accept 3 arguments:
- Reducer function
- Initial state
- Initializer function
The hook then returns an array of 2 items:
- Current state
- Dispatch function
Using the useState hook
Let’s check out the example of setting up a locale using
Pretty simple, right?
Using the useReduce hook
Now, let’s look into the
This code looks a bit more complex than the
This example involves a primitive value ‘locale’(string) which is not a complex object or an array.
So, this use case is more suitable for
Use-case of a state with an object
Now, let’s consider an example of a form taken from the React docs.
We have a user object with two fields: name and age.
Using the useState hook
Firstly let’s write the example using
If the logic of our code gets complicated then the setter function can be large and it will be difficult to handle it. Also, we have to take care of returning new items in every setter function using the spreading operator. This becomes very difficult to manage.
To simplify our lives,
we have a
useReducer hook to our rescue!
Using the useReducer hook
let’s write the same example using
Looks simple and clean.
useReducer is very similar to
but it lets us move the state update logic from event handlers
into a single function outside of our component.
The point to note is when we have a type of state as objects or arrays,
it is convenient to use
Thumb rules to decide when to use
Prefer useState if we have:
- Simple business logic
- Different properties that don’t change in any correlated way and can be managed by multiple useState hooks
Prefer useReducer if we have:
- Complicated business logic more suitable for a reducer function
- Different properties tied together that should be managed in one state object
We should consider incrementally adopting
as our state and validation requirements begin to get more complex,
warranting the additional effort.
useReducer for complex objects frequently,
if there are many pitfalls around mutation, introducing
could be worthwhile.
React docs recommend using a reducer if we often encounter bugs due to incorrect state updates in some components, and want to introduce more structure to its code.
useReducer is a matter of preference.
We can convert between useState and useReducer back and forth: they are equivalent!
We don’t have to use reducers for everything. We can mix and match!
If the project has gotten to the point of state management complexity, we may want to look at some even more scalable solutions, such as Mobx, Zustand, or XState to meet our needs.
But let’s not forget,
Add complexity only as needed.