Hooks

React’s new “hooks” APIs give function components the ability to use local component state, execute side effects, and more. React also lets us write custom hooks, which let us extract reusable hooks to add our own behavior on top of React’s built-in hooks.

React Redux includes its own custom hook APIs, which allow your React components to subscribe to the Redux store and dispatch actions.

We recommend using the React-Redux hooks API as the default approach in your React components.

The existing connect API still works and will continue to be supported, but the hooks API is simpler and works better with TypeScript.

These hooks were first added in v7.1.0.

Using Hooks in a React Redux App

As with connect(), you should start by wrapping your entire application in a <Provider> component to make the store available throughout the component tree:

const store = createStore(rootReducer)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

From there, you may import any of the listed React Redux hooks APIs and use them within your function components.

useSelector()

Allows you to extract data from the Redux store state, using a selector function.

The selector function should be pure since it is potentially executed multiple times and at arbitrary points in time.

The selector is approximately equivalent to the mapStateToProps argument to connect conceptually. The selector will be called with the entire Redux store state as its only argument. The selector will be run whenever the function component renders (unless its reference hasn’t changed since a previous render of the component so that a cached result can be returned by the hook without re-running the selector). useSelector() will also subscribe to the Redux store, and run your selector whenever an action is dispatched.

However, there are some differences between the selectors passed to useSelector() and a mapState function:

  • The selector may return any value as a result, not just an object. The return value of the selector will be used as the return value of the useSelector() hook.

  • When an action is dispatched, useSelector() will do a reference comparison of the previous selector result value and the current result value. If they are different, the component will be forced to re-render. If they are the same, the component will not re-render.

  • The selector function does not receive an ownProps argument. However, props can be used through closure (see the examples below) or by using a curried selector.

  • Extra care must be taken when using memoizing selectors (see examples below for more details).

  • useSelector() uses strict === reference equality checks by default, not shallow equality (see the following section for more details).

There are potential edge cases with using props in selectors that may cause issues. See the Usage Warnings section of this page for further details.

You may call useSelector() multiple times within a single function component. Each call to useSelector() creates an individual subscription to the Redux store. Because of the React update batching behavior used in React Redux v7, a dispatched action that causes multiple useSelector()s in the same component to return new values should only result in a single re-render.

Equality Comparisons and Updates

When the function component renders, the provided selector function will be called and its result will be returned from the useSelector() hook. (A cached result may be returned by the hook without re-running the selector if it’s the same function reference as on a previous render of the component.)

However, when an action is dispatched to the Redux store, useSelector() only forces a re-render if the selector result appears to be different than the last result. As of v7.1.0-alpha.5, the default comparison is a strict === reference comparison. This is different than connect(), which uses shallow equality checks on the results of mapState calls to determine if re-rendering is needed. This has several implications on how you should use useSelector().

With mapState, all individual fields were returned in a combined object. It didn’t matter if the return object was a new reference or not - connect() just compared the individual fields. With useSelector(), returning a new object every time will always force a re-render by default. If you want to retrieve multiple values from the store, you can:

  • Call useSelector() multiple times, with each call returning a single field value

  • Use Reselect or a similar library to create a memoized selector that returns multiple values in one object, but only returns a new object when one of the values has changed.

  • Use the shallowEqual function from React-Redux as the equalityFn argument to useSelector(), like:

    import { shallowEqual, useSelector } from 'react-redux'

    // later const selectedData = useSelector(selectorReturningObject, shallowEqual)

The optional comparison function also enables using something like Lodash’s _.isEqual() or Immutable.js’s comparison capabilities.

useSelector Examples

Basic usage:

Using props via closure to determine what to extract:

Using memoizing selectors

When using useSelector with an inline selector as shown above, a new instance of the selector is created whenever the component is rendered. This works as long as the selector does not maintain any state. However, memoizing selectors (e.g. created via createSelector from reselect) do have internal state, and therefore care must be taken when using them. Below you can find typical usage scenarios for memoizing selectors.

When the selector does only depend on the state, simply ensure that it is declared outside of the component so that the same selector instance is used for each render:

The same is true if the selector depends on the component’s props, but will only ever be used in a single instance of a single component:

However, when the selector is used in multiple component instances and depends on the component’s props, you need to ensure that each component instance gets its own selector instance (see here for a more thorough explanation of why this is necessary):

useDispatch()

This hook returns a reference to the dispatch function from the Redux store. You may use it to dispatch actions as needed.

Examples

When passing a callback using dispatch to a child component, you may sometimes want to memoize it with useCallback. If the child component is trying to optimize render behavior using React.memo() or similar, this avoids unnecessary rendering of child components due to the changed callback reference.

The dispatch function reference will be stable as long as the same store instance is being passed to the <Provider>. Normally, that store instance never changes in an application.

However, the React hooks lint rules do not know that dispatch should be stable, and will warn that the dispatch variable should be added to dependency arrays for useEffect and useCallback. The simplest solution is to do just that:

Last updated

Was this helpful?