What is the useReducer hook?

useReducer is there for you to handle state, just like useState does but a reducer has more advantages than just useState and works best for more complex state management.

If you ever worked with reducers (probably through redux or other means), you probably know that a reducer just accepts action object and then returns a state based on that action.

At first, this may not sound that useful (to some) and for the most part, you may not need a reducer to handle state for you.

When to use

There are some cases where useReducer hook will be useful to you (including but not limited to):

When dealing with a lot of states

The state you are dealing with depends on each other.

For a complex logic where debugging is essential

How to use

Here is a simple example just to show you some syntax

A very basic example of useReducer

When useReducer is really useful (An example of a use case)

Okay, but I could just do the same with useState

That’s a valid statement, that’s why I will show you an example of a case where useReducer is (almost) essential.

Let’s take a look at this scenario:

Here we have a component that simply keeps track of a string array and allows you to display them by keeping track of the current index

This works well, but what if in the future we want to allow other components to pass an array as default like this:

This will work for the most part, but what if the defaultArray prop change? Our component will not know to update the array state and it will remain using an old prop. There is an easy fix!

Now the array state will update when the defaultArray prop has changed.

Using the useEffect hook, it will listen to change on the defaultArray prop and update the array. But!

Your boss comes knocking on your door saying that users have been complaining how the items they have added keep disappearing when a change to the defaultArray is made, he wants you to make sure that any item the user added will not be erased when the defaultArray is changed.

In programming, there are many solutions to one problem but you may end up with something like this:

useEffect will cause an infinite loop here

This will cause an infinite loop because useEffect will run every time array state or arrayLength will change, and you set them both in the useEffect, meaning it will run infinitely.

Removing the dependencies from the array is also not really an option. (but that’s for another article) I will just leave this quote from the React.js useEffect docs

Note If you use this optimization, make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect.

Otherwise, your code will reference stale values from previous renders.

You could try to go with other solutions, something like saving the added items to a different array state and all of that but that just makes things more complicated down the round and there is more state to keep track of now, what if your boss comes again and ask for a change again or request a new feature? The component might grow too big or messy.

This is where useReducer finally comes into play

Let’s refactor the whole thing with useReducer

With useReducer, not only the code looks much cleaner, it’s also easier to debug. most of the logic is moved out of the component and we reduced re-renders.

Our component no longer causes an infinite loop anymore and if our boss comes again with a new request, it will be much easier to implement now.

Conclusion

We have seen the power of useReduer, it can really help if your component is complex and require a lot of states the is depended on each other.

However, if your component is simple, don’t rush to use it. sometimes you are better off with just useState.

I hope you’ve learned something new today. Please leave a comment if you have feedback or question and have a nice day :)