Batching in React

Let’s understand batching in react 17 and earlier

Aamir Saleem
2 min readMay 10, 2022
Photo by Lautaro Andreani on Unsplash

Let’s discuss about useState hook before getting into batching.

import React, { useState } from 'react';

function Counter() {
const [count, setCount] = useState(0);

useState returns a pair of values, first is the current state and second is a function which helps us to update the state.

To update the state we can call setCount. Whenever we call the setCount with a new value, react re-renders the component.

Let me reiterate: we think that every time the update method is called with a new value, react will render the component right away.

This assertion, however, is just half-true. Consider the following scenario.

function App() {
const [foo, setFoo] = useState(false);
const [bar, setBar] = useState(false);
function handleClick() {
setFoo(true); // Does not re-render yet
setBar(true); // Does not re-render yet
// React will only re-render once at the end (that's batching!)
}
return (
<div>
<button onClick={handleClick}>Change states</button>
</div>
);
}

DEMO

In this scenario, we have two state updates in a single click event. If we continue our partial understanding about useState, component should render twice. One after foo has been updated, and the other after bar has been updated.

Here’s an example of the flow

  • After foo update: { foo: true, bar: false }
  • After bar update: { foo: true, bar: true }

But if you run the given code, you’ll observe that react only performs a single re-render although the state has been updated twice.

This is possible thanks to batch updating. React uses batching to combine multiple state updates into a single re-render. This improves performance by avoiding unneeded re-renders.

Because of batching, the rendered state will be { foo: true, bar : true }.

Batching, however, does not always work in every situation. React does not batch outside event handlers. By default, updates inside of promises, setTimeout, native event handlers, or any other event are not batched.

Let’s make some modifications in the above scenario to update states inside the promise. In this case, instead of one re-render component will be re-rendered twice.

function App() {
const [foo, setFoo] = useState(false);
const [bar, setBar] = useState(false);
function promisifyBatch() {
Promise.resolve().then(() => {
// React 17 and earlier does NOT batch these
setFoo(true); // Causes a re-render
setBar(true); // Causes a re-render
});
}
return (
<div>
<button onClick={promisifyBatch}>Change states</button>
</div>
);
}

Demo: Promisify batch

Here’s how the flow will look like.

  • After foo update: { foo: true, bar: false }
  • After bar update:{ foo: true, bar: true }

React 18 is out! And it has brought some new features to React. One of the cool feature is automatic batching. Will talk about it in another article.

If you liked the article, please clap to it and share it!

--

--