If you search “Redux hooks” on Google, you won’t find a lot of resources about the cool new React-Redux hooks API. What you will find are bunch of articles about how to use React hooks as a replacement for Redux and other state management libraries.
If these improvements make you feel comfortable with using React to manage your application state without an external library, go for it! But React hooks are by no means the death of state management libraries like Redux. In fact, React-Redux version 7.1.0, released in June 2019, provides developers with its own set of hooks, with methods like
useDispatch(). Like React’s hooks API, these hooks let us cleanly organize our logic within the body of a functional component. They also eliminate the need to wrap our components in a higher-order
connect() component to connect to our store.
Let’s look at a ridiculously simple example to see how this works. (This assumes basic knowledge of how React and Redux applications work.)
Here we have a web page that lets you increment and decrement a counter. Super exciting, right? Behind the scenes, we have a whole React and Redux app setup to manage the state of the counter. (Fork this GitHub repo and play around with the code!)
This is business as usual for Redux. The new hooks API doesn’t reduce this part of the boilerplate. Now let’s look at how we connect our store to the React app with the counter:
Now let’s look at how our App component would get access to data from the Redux store without using the React-Redux hooks API:
This is how we get our simple counter app to work with React and Redux. But that’s a lot of boilerplate for something so simple. Let’s take a look at what’s going on here. First of all, we have a constructor that does nothing but give our class component access to the props being passed down to it. This component doesn’t actually need to be a class component since it’s not using local state or any lifecycle methods, so let’s quickly refactor it to a functional component so we can bring in the hooks:
Okay, that’s a bit nicer, but it’s still more complicated than it needs to be. We still need to define
mapDispatchToProps() functions to connect to the Redux store, and wrap our App component in the
connect() higher-order component so we can pass these pieces of the store and dispatching functions down to our App component as props. We also have to write
this.props over and over again (or, to avoid that, we can use object destructuring assignment like I did to assign our props to variables) in order to access these pieces of the store and dispatching functions. It’s all a bit messy, isn’t it? Let’s clean this up a bit.
First, let’s look at
useSelector(). This new React-Redux hook takes the place of
mapStateToProps() and allows you to directly hook into your Redux store without needing to pass state as props from a higher-order component. This function takes a callback as an argument. That callback takes the entire Redux store as its argument, but you don’t have to worry about grabbing the store yourself, because
useSelector() gets it from the Provider that we wrapped our App component in. In the body of the callback, you can return whichever piece of the store you want to have access to and save it as a variable in your component.
Since our Redux store’s initial state has a
count property with the initial value of
0, we can write
const count = useSelector(store => store.count) which selects the
count property from our store and assigns it to the
count constant we just declared. Before we press any buttons, that variable will have the value of
0. Let’s refactor our component to use the
This is a lot nicer already. We can get direct access to values from our Redux store now, and not rely on some higher-order component we didn’t write to pass it to our component as props. We can reference our
count constant anywhere in the body of our component and it will have the current value from our Redux store. If any actions are dispatched that update the
count property in our store, our
count constant will be updated as well. We can simply call
useSelector() again with a different selector and assign it to another variable if we need to make another selection from the store.
But, speaking of dispatching actions, our
mapDispatchToProps() function still forces us to use
connect() to get functions as props that we’d rather directly access in our component. Let’s do something about this.
The other main React-Redux hook,
useDispatch(), takes care of this for us. This one is super simple. Just call
useDispatch() in your component, and it will return a function you can use to dispatch actions to your Redux store. Pass a call to an action creator to this returned function, and it will work just like a function from
Let’s refactor our component one last time to implement the
Now that we can access our store and the dispatch function directly in our component, there’s no longer any need to wrap
App in a higher-order component to pass anything to it as props. This results in much cleaner code where everything is defined where it’s relevant. If you need to change any logic pertaining to Redux, you won’t have to look outside of the body your component anymore. Now, everything is nicely contained.
Obviously, this example is so simple that it hardly makes sense to use Redux here (or even React, really). But these hooks can be used the exact same way they are here, even if they’re in a more complex component that also uses React hooks like
(For a more complex example of how to use React-Redux hooks along with TypeScript, check out this GitHub repo showing how to build a to-do app with these technologies.)