This video is available to students only

Using the useReducer Hook

This final lesson eschews all external redux libraries and swaps in the use of React's built-in useReducer Hook and Context tools.

Using the useReducer Hook#

In this third and final lesson of the module, we’re going to go over another redux alternative, this one using no external libraries. Instead, we’ll be using a combination of React’s own useReducer Hook and the built-in Context system to pass both state and a dispatching function to various components.

You may remember we briefly introduced the useReducer Hook in our React Hooks Deep Dive module, but said we’d be covering it later on. Well that time has come, so let’s get learning!

By the way, I also have a great article on this subject available on my own website if you’d like to see more examples of the useReducer Hook in action.

Using useReducer and Context#

The useReducer Hook is provided by React natively without any third-party requirements. It’s quite a simple Hook to use, with its implementation looking like this:

You call the Hook, passing in a reducer function, initial state value (shown here as initialArg) and an optional third argument, init, which would be a function that allows you to lazy load your initial state value.

What the Hook returns is an array containing the current state of the app and a dispatch function to trigger state updates via actions, just as we have been doing so far.

The useReducer Hook focuses on what it does so well, but we still have a few missing pieces of the puzzle. For example, we no longer inherently have any central store mechanism, nor an obvious means to pass access to our app’s state or the dispatch function to different components. It’s not the end of the world, but it's common practice to create a centralized "store" mechanism just like we’ve seen with the other redux approaches this far, and then pass both the state and dispatch items across our app via React’s Context system.

Updating the project#

We have a few changes to make to our project again, starting with removing the React Redux libraries, and working our way through the same files from the last lesson to switch over to using the useReducer Hook.

Before we dive in, I’m just going to give you a heads-up that when we’re done, the resulting code will look a lot more like the first lesson’s code than the much more concise approach offered in the last lesson using Redux Toolkit.

Personally I feel that the useReducer and Context approach is somewhere between the two lessons we’ve covered so far. It is not as concise or smooth as that offered by the Redux Toolkit, but it does offer a much less opinionated approach, and doesn’t depend on any external libraries.

What’s more, the way we're going to tackle it here is one of a few different ways you could employ the useReducer Hook.

At its simplest it is a single line function call that is paired with a switch statement that updates some object values in a state item.

We’re going to be taking it up a gear in this lesson by creating:

  • a central redux store

  • a Context provider wrapper

  • and a combined reducer function just like we’ve already seen, to keep things equal between the three lessons.

If you decide that your project needs a redux system it's up to you to decide which type of implementation you prefer. There's no right or wrong solution or indeed a one-solution-fits-all approach. Sometimes, using the built-in offerings of useReducer and Context that we're exploring here will be enough. If you prefer a more opinionated and structured approach then the Redux Toolkit will work best for you. Once we've finished the module you'll have a more informed set of choices that you can explore using your own ideas and projects. I'd highly recommend playing around with them in a code playground, such as, to find which works best for you.

Switching up dependencies#

Just like the last lesson, let’s start by removing what we don’t need from our project. In this case, we’re going to remove the two packages, @reduxjs/toolkit and react-redux.

This time I’m just going to issue the yarn command, yarn remove @reduxjs/toolkit react-redux.

With that done, let’s start with some of the foundational work and build the changes up from there.

Removing configureStore.js#

Dead easy one to start with - find the /config folder that contains the configureStore.js file and just delete it altogether. We’ll still be creating the idea of a store, but we’ll do the work in our central reducers.js file this time.

This folder and file would be unused dead weight, so get it deleted and let’s move on.

Editing index.js#

We’re beginning our edits with the index.js file this time as there’s very little to change and it’s largely all removals.

Open up the file and let’s change up the imports around redux things:

Notice that the top imports are the same, but we’ve removed the store we brought in previously from our configureStore.js file which no longer exists.

We’ve also changed the Provider import to StoreProvider and changed the import location from react-redux to our reducers.js file. We’ll build out this new StoreProvider component later, but let’s import it here and use it right now.

With our StoreProvider import at the ready, simply use it to directly replace the <Provider> component that’s currently wrapping our <App/> component.

The changed file should look like this:

Editing eventReducer.js#

Let’s move onto the eventReducer.js file. Open it up and familiarize yourself with the current code we used alongside the Redux Toolkit. Unfortunately, our new code won’t look quite as neat and tidy as this, but it won’t be as long and unwieldy as in the first lesson.

Remove everything in this file except for the uuid import at the top.

Now, we won’t need to create any action functions this time, but we will be reinstating our action types. Let’s create the simple JavaScript key:value object now:

There we go, pretty much identical to those from the first lesson. Next, let’s create our eventReducer variable, complete with switch statement to work through the possible action types, and export it from the file as the default export.

This should look very familiar as it's virtually identical to the reducer function from lesson 1. There are a couple of subtle differences here, mainly where we’re referencing the action.payload value directly, rather than extracting it via destructuring into separate variables.

That aside, we still have to create a copy of state with our updates applied and return it from our matching cases. Everything else should look about the same though and it’s a pattern that you’ll start to see again and again when you get more adept with redux - this idea of adding items to arrays, changing values in a particular item in an array, and removing items from an existing array. You’ll see heavy and frequent use of both the map() and filter() functions as they both return a copy of an existing array which is perfect for us as we don’t want to affect the original state.

With all that wrapped up, let’s save and close the completed file which now looks like this:

Editing reducers.js#

We’re going to move on to arguably the most complex edits now, mainly due to the fact that we’re having to roll our own store and provider offerings. We’ll be introducing some unexplored concepts here. We didn’t have to do quite as much wiring up in the previous lessons because React Redux helps out a lot and Redux Toolkit offers a big dollop of black magic, doing almost everything for us.

Open up the reducers.js file and clear it out completely. Both the previous lessons imported the other reducers into this file and merged them all into a single offering using the combineReducers function. We don’t have access to such a function now that we’re on our own, so we’ll have to make one.

We’re also going to need to create a helper function that will create actions for us, as well as building a store context and adding both state and dispatch items to it so that other components can consume them across the app.

Let’s start with some imports. We’re pulling in a lot of things from React, including the new useReducer Hook. We’ve got our initial state and our events reducer that we just finished changing.

Next, we’ll create our own combineReducers function:

It might look a little fussy and tricky to read, but we’re effectively going to pass this function an object that has a set of key:value pairs representing reducerKeyName:actualReducerFunction. What we do then is return a sub-function that accepts a state and action argument. It is this sub-function that will be called by the useReducer Hook (as we’ll see in a moment). It almost acts like a reducer factory of sorts.


This page is a preview of Beginner's Guide to Real World React

No discussions yet