Back to posts

When to useState vs useReducer - a simple guide to help you decide.

February 10th, 2023 - 10 minute read

gray lighthouse on islet with concrete pathway at daytime, William Bout

Have you ever wondered when to use the `useState` and `useReducer` hooks? I have, and I've found that there's a simple way to decide. I'll show you how to use this simple rule to decide when to use either or both.

Hooks were first introduced into the React community in version 16.8. They’re functions that let you “hook” into a component’s state. Hooks work only inside functional components.

`useState` is the most common hook and it allows you to add state to a functional component. State is data, usually data that can change over time, that causes the component to re-render when it's updated.

`useState` is most useful when you have a single piece of state that is simple to update. For example, a boolean `isOpen` value, or some other primitive value such as text input.

`useReducer` is similar to `useState`, but it's more useful when you have multiple pieces of state that are related to each other.

Let's look at an example. Let's say we have a component that has a button that increments and decrements a counter. We can use `useState` to manage the counter state.

This is a contrived example, but it's a good place to start. Now, let’s get our simple counter to work with `useReducer` just to get familiar with the basics.

Essentially, with `useState`, you destructure 2 values: the current state (count); and a set/update function (setCount). Then in between the `useState` function, you pass in the initial state value (0 ).

`useReducer` on the other hand returns an array with exactly 2 items: the current state; and a dispatch function. Then in between the `useReducer` function, you pass 2 arguments: a reducer function; and the initial state value. There's a third, optional init argument but it can be omitted.

The reducer function takes 2 arguments: the current state value; and the action value passed to the dispatch function. Scroll back up and see if it makes more sense. Yeah? Nope? Keep reading.

Cool, so technically they do the same thing?

Yes, exactly! They are equivalent. You can always convert between `useState` and `useReducer` back and forth. Personally, I prefer to use `useReducer` when I have more complicated state because it's flexible and allows you to do more things. It's also a bit more complicated to use, but it's worth it. Let's look at another example.

Let's create a to-do list where we can add, edit, mark as complete or incomplete, and delete todos. We'll use both `useState` and`useReducer`. Ready? Let's go!

`useState` implementation:

`useReducer` implementation:

Now, let's look at the code. There isn't much difference, is there?

Also, unlike our previous example, we're using a switch statement in our reducer function because we have multiple actions that we need to handle. Kind of like Redux, right?

This is just a convention though. We can also use if/else statements or just regular objects, but I prefer the switch statement because it's easier to read.

If you’re a Redux fanboy, you can think of `useReducer` as a local version of Redux. That said, you don't need to know Redux to use `useReducer`. You may not even need to use Redux at all while working with React.

Notice that the `useReducer` version has a bit more code. While that is true, think of it this way.

Assume our PM comes to us and says “Hey, we need to add a couple of new features to our todo app. We need to add a feature to filter todos by completed or incomplete. We also need to add a feature to sort todos by date created or date modified."

With `useState` we would have to add a bunch of new state variables and update functions. Depending on how many new features we need to add, we might end up in useState hell. Kind of has a judgmental ring to it, doesn't it? Yeah, I'm judging you.

useState hell is when you have a lot of useState variables and update functions. It's a nightmare to maintain and debug.

With `useReducer` we would only have to add a couple of new cases to our reducer function. That's a lot less code to write, maintain, and debug. It's also easier to reason about because you have all of your state logic in one place. Even better, you can extract the reducer function to a separate file and import it into your component. That way, your component file is cleaner and easier to read.

Which one should you use?

It depends. There's no wrong answer here. It's like koalas or babies.

If you have a simple/independent state, use `useState`. If you have a more complicated state, use `useReducer`. If you're not sure, use `useState` and then refactor to `useReducer` if you need to. It's easier to refactor from `useState` to `useReducer` than the other way around.

Let's look at one more example to further illustrate the difference between `useState` and `useReducer`. This time, we'll work with text input fields.

Here's a form that uses `useState` to manage the state of the input fields. See if you can refactor it to use `useReducer`.

Here's the solution. How did you do? Did you get it right? Did you come up with a different solution? Let me know in the comments. Dang! I really should add a comment section. I'll do that soon. Promise.

Conclusion

Summary:

  • use `useState` when you have a simple/independent state.

  • use `useReducer` when you have a more complicated state that involves multiple sub-values or when the next state depends on the previous one.

  • Other than these, there's no right or wrong answer. It's all about what works best for you and your team. Both are great tools to have in your React arsenal. But like I said earlier, it's easier to refactor from `useState` to `useReducer` than the other way around. So, if you're not sure which one to use, start with `useState` and then refactor to `useReducer` if you need to.

    That's it for this post. I hope you learned something new. If you did, or if you have any questions, I'd love to hear from you. You can reach me on Twitter @dayoawobeku or send me an email.

    Until next time, happy hacking!