---
title: Using Redux with React Hooks
teaser: 'React Redux launched support for Hooks. We will explore the new `useSelector`
  and `useDispatch` hooks and look into the tradeoffs of using these hooks versus
  the `connect` higher-order component.

  '
tags: react,redux,javascript,web
author: Stephen Hanson
published_on: 2019-07-30
---

**Note, 2023**: This article was most relevant when Redux initially launched
its hooks API as people began migrating to hooks. While it probably isn’t as
useful as it was then, it is still accurate in 2023 and relevant for anyone who
is working with a legacy codebase. You might also be interested in our newer
post: [Redux Toolkit is the official way to write Redux
apps](https://thoughtbot.com/blog/getting-started-with-redux-toolkit).

---

React Redux recently released [version 7.1][version], which includes long
awaited support for React Hooks. This means that you can now ditch the `connect`
higher-order component and use Redux with Hooks in your function components.
This post will take a look at how to get started using Redux with Hooks and then
explore some gotchas of this approach.

## What are Hooks?

Hooks were added to React in 16.8 and allow you to access things like state,
React lifecycle methods, and other goodies in function components that were
previously only available in class components.

For example, a React class component like this:

```jsx
class Count extends React.Component {
  state = {
    count: 0,
  };

  add = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.add}>Add</button>
      </div>
    );
  }
}
```

Could be rewritten as a function component using Hooks like this:

```jsx
const Count = () => {
  // state variable, initialized to 0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Add</button>
    </div>
  );
};
```

The code is more concise and allows teams to make more use of function
components without having to convert them to class components as soon as they
need state or access to the React lifecycle. This post isn’t really about Hooks
in general, so I’d check out the excellent [Hooks documentation][hooks] if you'd
like to learn more.

## How to use Redux with Hooks

React Redux now includes its own `useSelector` and `useDispatch` Hooks that can
be used instead of `connect`.

`useSelector` is analogous to `connect`’s `mapStateToProps`. You pass it a
function that takes the Redux store state and returns the pieces of state you’re
interested in.

`useDispatch` replaces `connect`’s `mapDispatchToProps` but is lighter weight.
All it does is return your store’s `dispatch` method so you can [manually
dispatch actions][dispatch]. I like this change, as binding action creators can
be a little confusing to newcomers to React Redux.

Alright, so now let’s convert a React component that formerly used `connect`
into one that uses Hooks.

Using `connect`:

```jsx
import React from "react";
import { connect } from "react-redux";
import { addCount } from "./store/counter/actions";

export const Count = ({ count, addCount }) => {
  return (
    <main>
      <div>Count: {count}</div>
      <button onClick={addCount}>Add to count</button>
    </main>
  );
};

const mapStateToProps = (state) => ({
  count: state.counter.count,
});

const mapDispatchToProps = { addCount };

export default connect(mapStateToProps, mapDispatchToProps)(Count);
```

Now, with the new React Redux Hooks instead of `connect`:

```jsx
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { addCount } from "./store/counter/actions";

export const Count = () => {
  const count = useSelector((state) => state.counter.count);
  const dispatch = useDispatch();

  return (
    <main>
      <div>Count: {count}</div>
      <button onClick={() => dispatch(addCount())}>Add to count</button>
    </main>
  );
};
```

I like that using Redux with Hooks is a little bit simpler conceptually than
wrapping components in the `connect` higher-order component. Another benefit of
not using the higher-order component is that you no longer get what I call
“Virtual DOM of death”:

<img
  alt="Deeply nested DOM tree due to components wrapped with connect function"
  style="width:260px; max-width: 100%"
  src="https://images.thoughtbot.com/blog-vellum-image-uploads/BbwVghQmSvetg9BiHbHx_virtual-dom-of-death.png"
/>

I suggest reading the full [Redux Hooks documentation][redux-hooks] for more
information.

## useSelector gotchas

`useSelector` diverges from `mapStateToProps` in one fairly big way: it uses
strict object reference equality (`===`) to determine if components should
re-render instead of shallow object comparison. For example, in this snippet:

```jsx
const { count, user } = useSelector((state) => ({
  count: state.counter.count,
  user: state.user,
}));
```

`useSelector` is returning a different object literal each time it's called.
When the store is updated, React Redux will run this selector, and since a new
object was returned, always determine that the component needs to re-render,
which isn't what we want.

The simple rule to avoid this is to either call `useSelector` once for each
value of your state that you need:

```jsx
const count = useSelector((state) => state.counter.count);
const user = useSelector((state) => state.user);
```

or, when returning an object containing several values
from the store, explicitly tell `useSelector` to use a shallow equality
comparison by passing the comparison method as the second argument:

```jsx
import { shallowEqual, useSelector } from "react-redux";

const { count, user } = useSelector(
  (state) => ({
    count: state.counter.count,
    user: state.user,
  }),
  shallowEqual
);
```

There is a section in the [Redux Hooks documentation][redux-hooks-equality]
that covers this in more detail.

## Redux with Hooks vs. Connect higher-order component

Hooks are great. They allow for using function components in ways that weren't
previously possible, and the community is clearly moving in the direction of
using function components and hooks when possible. The [React
documentation][function-components] states:

> We intend for Hooks to cover all existing use cases for classes, but we will
> keep supporting class components for the foreseeable future.

While there is no need to race off and convert all your existing code, our
recommendation for new code is to generally prefer function components and Hooks
over using class-based components and higher-order components. Using the Redux
Hooks aligns with this recommendation and provides other key benefits
over `connect`.

The main benefit of using the Redux Hooks is that they are conceptually simpler
than `connect`. With `connect`, you are wrapping your component and injecting
props into it. This can make it difficult to determine in the component which
props come from Redux and which are passed in. If you are using TypeScript,
correctly defining the types of connected components can be quite a chore for
this reason. The Redux Hooks, on the other hand, are just regular hooks that
don't modify the public interface of your component. In TypeScript projects, I
create my own `useSelector` that is typed to my store, and then I get
type-checking everywhere I use it. Easy!

React Hooks are a useful new feature, and React Redux's addition of
Redux-specific hooks is a great step toward simplifying Redux development.

[version]: https://github.com/reduxjs/react-redux/releases/tag/v7.1.0
[hooks]: https://reactjs.org/docs/hooks-intro.html
[redux-hooks]: https://react-redux.js.org/api/hooks
[redux-hooks-equality]: https://react-redux.js.org/next/api/hooks#equality-comparisons-and-updates
[dispatch]: https://github.com/reduxjs/react-redux/issues/1252#issuecomment-488160930
[function-components]: https://reactjs.org/docs/hooks-intro.html#gradual-adoption-strategy
