Clean Up Redux Code With React-Redux Hooks PDF
Clean Up Redux Code With React-Redux Hooks PDF
preducks, a React-Redux prototyping app (with an accompanying npm module) that generates
boilerplate code using React-Redux hooks and TypeScript.
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.
But this was never the point of hooks. React hooks were made to allow
developers to write functional components that can do all the things we once
needed class components for, like using state or lifecycle methods. React hooks
improve the developer experience by optimizing the organization,
maintainability, and readability of React code. They allow us to share logic
between components without using complicated design patterns like render
props or higher-order components, and they cut down on the dense boilerplate
required by JavaScript classes. They don’t really add any new functionality to
React; functional components using hooks can’t do anything that class
components can’t. But they do allow us to write much cleaner code.
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 useSelector() and 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!)
1 export const increment = count => ({
2 type: 'CHANGE_COUNT',
3 payload: count + 1
4 });
5
6 export const decrement = count => ({
7 type: 'CHANGE_COUNT',
8 payload: count - 1
9 });
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:
1 import React from 'react';
2 import {render} from 'react-dom';
3 import App from './components/App.jsx';
4 import {Provider} from 'react-redux';
5 import store from './reducers/counterReducer';
6
7 render(
8 <Provider store={store}>
9 <App />
10 </Provider>,
11 document.getElementById('root')
12 );
Business as usual once again. When we call render(), we wrap our App component in the Redux
Provider component to give our application access to the Redux store. React-Redux hooks don’t
change this either.
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:
A React component connecting to the Redux store without React-Redux hooks.
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 mapStateToProps() and 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.
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()
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 mapDispatchToProps() .
Let’s refactor our component one last time to implement the useDispatch()
hook:
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 useState() or useEffect() .
(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.)