How I reduced the code in my Redux app by using Redux Hooks.
Here’s how you can simplify the Redux bindings in all of your components to help reduce your React Redux boilerplate.
I recently wrote an article that compared the exact same app built with React and again with React + Redux.
The code for the app that had Redux used
connect() bindings to hook up our components to our store. This meant that we had things such as
mapDispatchToProps adding several lines of code to each of our container* components.
*A container component is typically an entry point for our Redux store. These files would then pass Redux store state down to subcomponents as props. In our example, our container component is App.js. But if you were using React Router, you may decide to treat each route (eg. Index.js, About.js etc) as a container component. Use of the word “container” is simply a semantic word to help a developer differentiate it from a ‘regular’ component. There is no difference in how either component is created, although you may choose to put your container components inside of a container folder in your app directory if you choose to.
Anyway, a couple of people mentioned that I should have used Hooks to simplify those Redux bindings.
Now please bear in mind that this isn’t an article designed to preach that you should go and rewrite all of your previous Redux code — because you definitely shouldn’t be wasting time rewriting something if it already works perfectly. However, I do think it would be a good idea to shed some light on what your code would look like if you swapped out the old Redux bindings for the new Hooks-based ones. That way you can look to leverage these new bindings for the next new project you find yourself working on.
Note: We won’t be deep-diving into the code used in our actions, reducers or store (or any of the other files that usually sit inside of the redux folder). As this is a continuation of a previous article, we recommend that you go and read that article if you are looking to understand how the lower-level parts of Redux work. The link can be found here.
Now our To Do app is pretty simple, so fortunately we only had one file that needed to use our Redux
connect() bindings. That file also didn’t have to pull in too much stuff from our Redux store/actions. However, the file still looks quite messy, as we can see from the image below:
Here’s what our new App.js file looks like with the our Redux Hooks bindings:
One immediate difference between the two screenshots here is that everything is separated out in the first screenshot where we used the
connect() bindings, whereas everything is encapsulated inside of our
App variable in the second screenshot when we use Redux hooks. This encapsulation is required as, quite simply, we cannot use hooks outside of a React functional component.
So with that small matter out of the way, let’s go through those five lines of code inside of
App to understand how this all works:
useSelector() is a hook that provides access to our Redux store’s state. This hook takes a selector function as an argument. The selector is called with the store state. So here we called our argument
store and then accessed our
appReducer which had a
list object inside of its state. If you’re curious to understand how those parts connected, I suggest reading the previous article that covered this. By using
useSelector(), we effectively replace the need to use
mapStateToProps(), enabling us to directly hook into the Redux store without needing to pass state as props from a higher-order component.
In short, this hook creates a reference to that particular part of our state. We can then pass this around our app and whenever it gets updated by Redux, our reference gets updated as well.
Okay, so we have access to our state through hooks, but what about access to our dispatch functions?
useDispatch() is a hook that provides us with access to the redux
dispatch function. In the screenshot above, you can see that we assign
useDispatch() to a
We then create two more
const's that have identical names to the dispatch functions we want to create references to. You could choose to call them whatever you want, but this is the path I chose to take:
This may look a bit confusing at first, so let’s break it down further. We are creating functions that take in a param,
todo in the
redux_add function and
id in the
redux_delete function. These are basically the payloads that our dispatch functions require. Then our functions return the
dispatch that had been initially been given the value of
As it is a reference to the Redux dispatch function, we basically just pass in the function that we wanted to call, which in the case of
redux_add, is the
redux_add function that sits inside of
appActions, which was imported at the top of the file. You can also notice that we pass in the
todo param as its payload. We do the same thing with the
Now there are other ways that you could choose to write this. For example, I could have written this as:
This achieves the exact same thing and is basically what you would end up finding inside each function in the appActions.js file. If you choose to take this second route, be sure to import your Action Types instead of your App Actions, which means importing this:
instead of this:
In short, we use
useDispatch() to create local references to specific dispatch functions. This replaces our need to use
And then how do we pass these values to our components?
This final bit wasn’t wholly necessary, as I could have just passed each item into the
<ToDo/> component like this:
But I generally don’t like how this looks and wanted the code for the props object for both the
connect() bindings version and the Redux Hooks version to look as similar as possible - this was achieved by creating the
props object .
So there we have it!
We’ve reduced some of the boilerplate in our Redux app. Besides the Redux mental model, the boilerplate can be a concern for new devs to wrap their head around. Hopefully Redux Hooks can help to reduce the amount of head wrapping. We no longer have to worry about wrapping our components inside of
connect() Higher Order Components anymore!
Now you can focus on wrapping your head around more pressing concerns like asynchronous action creators!
If you’d like to review the repo used in this article, it can be found here: https://github.com/sunil-sandhu/redux-hooks-todo-2019
You can also compare it with the original Redux repo that used the old bindings here: https://github.com/sunil-sandhu/redux-todo-2019