Beginner's Guide to React 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.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Beginner's Guide to Real World React course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Beginner's Guide to Real World React, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

Thumbnail for the \newline course Beginner's Guide to Real World React
  • [00:00 - 00:24] 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 use reducer hook and the built-in context system to pass both state and a disp atching function to various components. You may remember we briefly introduced the use reducer hook in our React Hooks deep dive module, but we said we'd be covering it later on. While that time has come, so let's get learning.

    [00:25 - 01:58] 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 use reducer hook in action. The use reducer 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 can call the hook passing it a reducer function, initial state value, shown here as initial arg, and an optional third argument in it, which would be a function that allows you to laser 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've been doing so far. The use reducer hook focuses on what it does well, but we still have a few missing pieces of the puzzle. For example, we no longer inherently have any central star mechanism, not an obvious means to pass 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 star 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. 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 use reducer hook. Before we dive in, I'm just going to give you a little heads up that when we're done, the resulting code will look a lot more like the first lessons code than the much more concise approach offered in the last lesson using the Redux tool kit. Personally, I feel that use reducer and context approach is somewhere between the two lessons we've covered so far. It's not as concise and 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.

    [01:59 - 03:39] What's more, the way we're going to tackle it here is one of a few different ways you can employ the use reducer hook. At its simplest, it is a single line function that is paired with a switch statement that updates some object values in a state item. We're going to be taking this upper gear in this lesson by creating a central Redux star, 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 really no right or wrong solution or indeed a one solution fits all approach. Sometimes using the built-in offerings of use reducer 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 code signbox.io to find out which works best for you. 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 Redux.js toolkit and React Redux. This time, I'm just going to issue the yarn command yarn remove at Redux.js/toolkit React-Redux. With that done, let's start with some of the foundational work and build up the changes from there. Dead easy one to start with, find the /config folder that contains the config star.js file and just delete it altogether. We'll still be creating the idea of a start, but we'll do our work in the central reducers.js file this time. This folder and file would be unused deadware, so let's get it deleted and let's move on. We're beginning our edits with the index.js file this time and there's very little to change as it's largely all removals.

    [03:40 - 04:03] Let's open up the file and change the imports around the Redux things. Notice that the top imports are the same, but we've removed the star we brought in previously from our config star.js file which no longer exists. We've also changed the provider import to star provider and changed the import location from React Redux to our redu cers.js file.

    [04:04 - 05:55] We'll build out this new star provider component later, but let's import it here and use it right now. With our star provider imported already, simply use it to directly replace the provider component that's currently wrapping our app component. The change file should look like this. Let's move on to the event reducer.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 as unwieldy as in the first lesson. Remove everything in this file except for the UUID import at the top. 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 event reducer 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 one. There are a couple of subtle differences here and there, 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 stay without 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. 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 star and provide our offerings.

    [05:56 - 06:33] We'll be introducing some unexplored concepts here. We didn't have to do quite as much this wiring up in the previous lessons because React Redux helps out a lot and the Redux tool kit offers a big dollar 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 merge them all into a single offering using a combine reducers 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 out a star context and adding both state and dispatch items to it so that other components can consume them across the app.

    [06:34 - 09:23] Let's start with the imports. We're pulling in a lot of things from React including our new use redu cer hook. We've got our initial state and event reducer that we've just finished changing. Next we 'll create our own combine reducers function. Now it might look a bit 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 reducer key name and actual reducer function. What we do then is return a sub function that accepts a state and an action argument and it is this sub function that will be called by the use reducer hook as we'll see in a moment. It almost acts like a reducer factory of sorts. This sub function will be used by the use reducer hook but instead of a switch statement that matches action types it loops through the reducer's arguments keys and calls each reducer function in turn passing at the correct slice of state, the one that matches the same key value in the state object. In essence we've created a higher order function it returns a function that calls each reducer function to carry out any state updates. This return function is the one doing the state updates and returning a new copy of state. It might look a little weird but it will become clearer as we progress through the edits. Next we're going to call the combine reducers function passing in an object that contains our single reducer function events that we imported earlier. We'll stash this in a const for now and refer to it in a moment. I know that we only have one reducer here events that we imported from the event reducer file but what we're building here is a realistic offering that will scale. If we wanted to add more reducers here as our app grows all we have to do is import them and add them to the combine reducers call. You could skip these steps and just pass this singular reducer directly to the use reducer hook and spare yourself the complexity but at some point your app's going to scale and it's useful to have things in place now that will allow it to happen easily without having to pick apart the code. Next we want to define an exporter context instance. For that we'll be using the create context function provided to us by react. You'll remember this from the module on hooks and use context. Next we're going to define a start provider component that pulls together the result of the user use a hook. Our context and also returns a wrapped component instance that we already consumed in the index.js file. What's going on here is that we 're accepting a children property that we've grabbed from props. This component will be passed any child components via the children property. In our case this will be our entire app as this component wraps the app component as we recently seen during the index.js file edits. The first line in this component is the use of the use reducer hook. We pass it our root reducer variable which is the result of the combine reduces function and initial state. It returns us an array containing state and dispatch.

    [09:24 - 10:22] These are what we'll need to pass along to child components in our app. From here we're going to make a redox store. We're using the use memo hook here to prevent any unnecessary extra re-rendering. One of the criticisms leveled at this method of approaching redox is that any changes in state cause multiple re-renders of components. This might not be a particular issue in your app, it certainly won't be for us here, but I'm caution again about becoming too focused on optimizations. That said we're looking at a realistic scenario here and building for potential future scale. We'll use the use memo hook to keep an eye on state and only update the star value when that changes. Finally we're returning the star context.provider component passing the star value into the value attribute so that it's available across our apps when we need it . We're wrapping this component around our children property that we grabbed at the start. The very last thing to do here is to create a little nice adi in the form of a helper function. In the first lesson we had a bunch of separate yet specific action functions such as add event attendee.

    [10:23 - 10:53] Whilst we've not gone down that route this time, although we could have, it's still nice to have a little help in reducing repetitive code when we need to call the dispatch function and pass it an action. Very simple one here, we're creating an inline arrow function create action that accepts a type and a payload and returns them as a new object with keys with the same name. It might not look like much but it saves us from having to write the same messy looking code each time we want to pass an action to the dispatch function. We'll see an example of this shortly when we edit our first component. When complete, the reduces.js file now looks like this.

    [10:54 - 12:21] Now we're going to edit the event sign up list component. Open up the file and let's make some changes. Firstly the imports. We're routing ourselves to the React Redux imports as they're no longer necessary. We're also bringing in the use context hook here so we can grab hold of the values from the star we just made. Next we're removing the various action function that we had previously and replacing them with the action types actions instead. After this we're bringing in both the star context and create action helper from our reducers file. We have put two more changes to make to wire everything up. For the first we're going to replace the existing variables logic. Instead of the previous use selector and use dispatch hooks we've made use of the use context hook passing at the imparted star context and grabbing the result as an array of state and dispatch. You may remember this pattern of consuming context for our time in the use context hook lesson. Of course once we have both state and dispatch we can grab the event attendees from state and how is it in a nice convenience variable. The final change is to make a slight amendment to the click event of our buttons. We're still calling dispatch although it's not the same one we used in the last lesson now but instead of passing a specific action function such as toggle event attendance this time we're passing in the result of our create action helper.

    [12:22 - 12:59] We'll pass our helper an action type such as actions dot toggle attendance and either a value or an object that contains the changes we want to see instead. And that's it done. The completed component now looks like this. The last series of changes before we fire up the machine once again is inside the event signup form component. The changes here will be very similar to those we've just made in the event signup list component so let's start with the import and go from there. The react part is largely untouched except for the addition of the use context hook.

    [13:00 - 13:49] We swapped the add event attendee import for actions and lastly we've brought in both star context and create action once more. Now for the changes to the variables section. We're consuming the star context context and extracting out our state and dispatch and removing the use dispatch hook that we no longer need. With those in place let 's move on and make a small edit in the handle form submit event handler. We've removed the new event attendee object and created and added this as an inline object using the spread syntax to the updated dispatch function call where we've also added the add attendee action type. And believe it or not that's this component done. By abstracting the logic into event handler functions right from the start the JSX in this component has remained untouched throughout three whole lessons.

    [13:50 - 14:09] The complete component now looks like this. At last our big moment open up a terminal window and run the yarn start command waiting for the site to open in the browser. Looking around the UI you'll see that not much has changed.

    [14:10 - 15:02] We can continue adding new signups editing their attendance deleting them and everything works just as it did before. However although we haven't changed anything in the UI we have drastically changed the plumbing of the code that powers it. This is the second big change we've made to an existing redook system which is no small feat and you should be hugely pleased with yourself for sticking with it. From here on out you'll have a lot more confidence to implement a redook system in your own projects and recognize and work with similar systems in other projects. Throughout this module we've learned about the redook state management pattern how it fits in with React, some libraries that help power it and different options to implement it within a React project. And with that we'll close the books on this penultimate module. In the next and final module in this course we'll be putting everything we've learned to good use by building our very own day-to-driven app the dinosaur search app.