5 min read

Automatic Batching in React 18

React 18

In React, when the setState method is called, it triggers a re-rendering of the component. When considering class components, the setState method is often called once, as you can pass the whole state into it as a parameter. But with functional components using the useState hook, each useState hook will only update that specific state value. This means that if you have to update two states, you will need two useState calls, and this will result in two renders. React avoids this with the help of a technique called Batching.

What is Batching?

Batching is a simple technique where multiple state updates are combined together as one single state update that ultimately results in a single re-render, compared to several renders. As per the React documentation, “React may batch multiple setState() calls into a single update for performance”. This behavior is the same for class components using the setState method, and functional components using the useState hook. This technique intends to improve the performance of your application by reducing the number of re-renders. Batching happens for setState calls that are made inside a React event handler or synchronous lifecycle method.

Let’s see an example.

When you look at the image above, the setNumberCounter and setNoOfTimestClicked will each have one re-rendering of the component. With Batching in place, these two will be batched together as one, with only one resulting re-render. This behavior can be clearly highlighted in the screenshot given below as two button clicks have only resulted in 2 renders compared to 4 renders.

What is Automatic Batching?

Automatic Batching is a technique that was introduced with React v18 and is an upgrade to the previous batching technique that was used in prior versions of React. Before React v18, not all state updates were batched. 

For example, state updates through async code such as callbacks, and promises and browser API functions such as setTimeout and setInterval were not batched in versions prior to React 18. But with Automatic Batching, these were also batched, making your applications more performant.

Let’s have a look at an example to understand this concept even further.

In the code snippet given below, it can be seen that the incrementCounter method has been asynchronous and it has a resolving Promise in it.

Running the above code in a React 17 environment would result in two renders for each state update as shown below.

It can be clearly seen the console statement has been printed twice, even though there has been only a single increment in the counter. Even though batching is enabled in React v17, it does not handle async code as stated previously. Hence, the state updates were not batched resulting in two re-renders.

Let’s run the same code snippet in a React 18 environment and see how it differs from the latter.

It can be clearly seen in the screenshot above, that even though two state updates are done in an async function, it only results in a single render thanks to Automatic Batching while the previous version had two renders. Even though this looks like a small change, the performance increase will be worth it.

Now you might wonder, how does batching or automatic batching provide a performance increase? Batching reduces the number of renders taking place in state updates. Even though the time taken for these renders will be negligible in smaller applications, when your app grows in size and complexity, each render will take a considerable amount of time. This is especially important when involving parent components having several children components that are nested. In such a scenario, render in the parent component will trigger renders in each child component in a cascaded manner. This will cause a considerable performance impact if unhandled.

Wrapping up

Automatic batching is an upgrade to the batching technique provided by previous versions of React prior to React v18, which batches multiple state updates into one single update and results in only one re-render of the component.