Reducing useReducer

Leon
7 min readJul 13, 2022
courtesy of Morioh

To me, learning React is comprised of four parts. In order to understand React in the most simple way possible one must understand…Components, JSX, Props and State. The latter in which the useReducer hook does a great job at managing. While I won’t go into the four parts in detail, I think those are the most important concepts to learn and understand.

What I will go into detail about in this article though is the useReducer hook. The useReducer hook is an alternative to the useState hook. With the useReducer hook you can eliminate the need to use prevState (a reference to the previous state before a state update) and you can also use it to update multiple states at once. In the example I am about to walkthrough I do just that. A simple login app that takes an email and a password, validates them and allows the user to log in is what we’ll be working on today.

In this application we will be tracking the users input for both the E-Mail and Password fields. We will be validating that the email includes an @ symbol and that the password length is more than 6 characters long. I use the useReducer hook to gather both the input and validation of both fields. Here’s how…

Before I get into how I utilized the hook, let’s give an overview of what it is and how it works. As I mentioned in the beginning of the article the useReducer hook is similar to the useState hook. One way they are similar is the way they are declared. The useState hook is declared by returning a destructured array of two values, usually a variable name of your choice followed by that same variable name prefixed by “set” as shown below.

useState hook example

useReducer is declared in a similar way to useState in that it returns a destructured array of two values. The values are different though. Here is an illustration of how we call our useReducer function and I’ll explain each part below.

useReducer hook example

Our first value is a snapshot of our state, this is what our state is on render our initial state if you will.

Our second value is our dispatch function or method. This is method triggers an update to our state snapshot and tells our reducer the type of action to execute when it is called. More on this later.

Inside of our reducer function call we have our reducerFn this function listens to our dispatch function for an action update. It receives the latest state snapshot and returns a new, updated state.

The second argument in our useReducer call is the initialState this is our default state similar to putting a value inside the useState hook

default value in useState hook

lastly our initFn argument is optional and it is used to programmatically set our state.

Now let’s get into the meat and potatoes of using our new hook. Previously I mentioned that useReducer is capable of managing multiple state values at once. In this example project I did just that. Initially I managed the users email and password input separately using the useState hook as illustrated below.

the password state was managed exactly the same

converting both states to being managed by useReducer was simple. First we import the hook, obviously.

useReducer hook import

then we create a reducer function as well as a useReducer declaration. Once you familiarize yourself with the hook the order in which you do this shouldn’t matter. But for the sake of argument I’ll assume you’re new to it like me. So we’ll start with setting up our useReducer function. Like so.

to keep the code clean I named each value appropriately. I won’t go into what each part means because I explained in the section above. But I will explain our new value after emailReducer. In our useReducer call we have an object. As you may recall from the section above, our second argument in the useReducer function is our initial or default state. So we set the value of the users email to an empty string and its validity to null.

Now that we have our useReducer hook set up. We want to declare our reducer function. We will name it emailReducer like how we named it in the first argument of our hook because we want the hook to know what function to reference when the dispatch action triggers the state update. So we set up our emailReducer function like this.

so to explain this function. We take in two parameters, our state and our action. Then we return the update we want based on action type. The picture above doesn’t demonstrate that flow yet entirely, but it will soon. For now understand what the flow is:

dispatch function -> triggers reducer function -> reducer function looks for similar named function for action to take to update the state.

Note that when I said we’d be converting both the value state as well as the validity state for this useReducer hook implementation, this is what I meant. As you can see in the emailReducer function I’m returning an object with the key’s “value” and “isValid” .

Let’s move on. In our code we have an emailChangeHandler function. This function takes in the value that will be used by our Email input. I won’t go into setting this up because that’s not the scope of this tutorial. But I will explain how we use it in tandem with our useReducer hook.

For now let’s zero in our focus on the dispatchEmail function.

Conventionally the dispatch function is called with an object as the parameters. The object usually has a key with the name “type”, this type is then referenced in the action of the reducer function (emailReducer). Be sure to make sure the spelling is correct in both and they match. For a safer approach is not uncommon to declare a constant called ACTIONS with all the different types you plan on using in your reducers. This can then be referenced in your actions and dispatch functions. ACTIONS.type.(key value).

Now we have to double back to our emailReducer function and add some layers to it because as I said before the above snippet doesn’t explain the flow in depth.

now that we’ve set up our dispatchEmail function with a type and value, we return back to our emailReducer and add layers with actions to take based on the types and values. So here we add two conditions the first we say if the action type is ‘USER_INPUT’ which we named it in our dispatchEmail function, then we want to update our state’s “value” key to the value of that action. Concurrently we want to update the “isValid” key as well, but only if the ‘USER_INPUT’ value includes an @ symbol.

Next we have the ‘INPUT_BLUR’ type. Which is an action type I haven’t shown yet because it’s used in another function.

here we just want to take the updated state snapshot in the event that the focus changes or “blurs” on the webpage. We don’t care about the value here inside dispatchEmail function, so we don’t add it.

However in our emailReducer function conditional for when the action.type is ‘INPUT_BLUR’ rather than returning the action value we want to return the state value. Like this…

By default if the action.type inside our emailReducer function is neither of the types we explicitly define, it will return our default state value.

With our value and validity state being managed by useReducer now. We have less redundant code, more efficient code and we’re able to check our user’s input value and it’s validity all in one place.

As I continue to learn and implement React hooks my programming skills become stronger. useReducer is a more complex hook for sure but it’s usefulness is unmatched. I’m glad I took the time to learn it. I’m also glad you took the time to read this to the end, thank you! Please note that there may be an easier more efficient way to explain this hook than how I did, but this was the simplest way for me. I hope you enjoyed, look forward to sharing more with you soon.

For more information on how the useReducer hook works please visit the official React JS docs here

--

--