React Redux: performance considerations when dispatching multiple actions

Oliver Joseph Ash
Jan 27 · 4 min read

In a React Redux app, what happens when you dispatch multiple actions in a row?

When used out of the box without any performance optimisations, there are two primary concerns:

  • React will re-render multiple times
  • React Redux will re-evaluate selectors multiple times

There are well known and documented solutions to the “multiple React re-renders” problem, but the other problem is not so well known. In this article I’ll demonstrate both problems along with their respective solutions.

React re-renders multiple times

By default, React will re-render once for each dispatched action, including for actions that are dispatched together in the same tick of the event loop (except for actions dispatched inside event handlers).

As an example, here is a React app that fetches some data when a button is clicked, and then dispatches 2 actions:

(Full example can be found on GitHub and StackBlitz.)

When we profile this, we can see that React is rendering twice (once for each dispatched action):

Fortunately there is a well established solution to this: the batch function.

When we profile this again, we can see that React is now rendering only once:

React Redux re-evaluates selectors multiple times

The batch function only solves half of the problem:

Each time an action is dispatched, every connected component will be notified, and as a result all of the selectors used by those connected components must be re-evaluated. To say that another way: each time an action is dispatched, every selector in the app must be re-evaluated.

When we’re dispatching multiple actions in a row, this can get quite expensive. We only want to re-evaluate those selectors once, after all actions have been dispatched, rather than once for each dispatched action.

To demonstrate this, let’s add an expensive selector to our app. (To simulate an expensive selector I’m just blocking the main thread for 3 seconds.)

When we profile this we can see that React Redux is re-evaluating our expensiveSelector twice (once for each dispatched action):

Why does this happen? Redux notifies subscribers after each successfully dispatched action, and amongst those subscribers will be every connect ed component in the app.

To optimise this, we can utilise redux-batched-subscribe, which is a store enhancer that lets you debounce subscriber calls for multiple dispatches.

When we profile this again, we can see that React Redux is now re-evaluating our expensiveSelector only once:

Note that I used a single expensive selector here for demonstration purposes, but this optimisation may still be worthwhile even if your selectors are not that expensive—React Redux apps tend to use a lot of selectors, so it’s worth considering the aggregate cost of all your selectors when they are all ran at the same time. Furthermore, even if all selectors are correctly memoized (e.g. using reselect), the cost may still be high due to the equality checks React Redux must run on all selector outputs.

All of the code for this article can be found on GitHub and StackBlitz.

Unsplash Blog

Behind the scenes building the open photography movement at Unsplash.

    Oliver Joseph Ash

    Written by

    Unsplash Blog

    Behind the scenes building the open photography movement at Unsplash.

    Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
    Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
    Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade