State Update Batching
Overview
In React, multiple state updates are batched into a single update for better performance.
MultipleUpdates.jsx
import React, { useState } from "react";
function MultipleUpdates() {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
function handleClick() {
setCount((state) => state + 1);
setCount2((state) => state + 1);
}
return (
<div>
<p>
Count: {count} / {count2}
</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
Even though we call setCount
and setCount2
in the same function, React will batch the state updates into a single update, which leads to a single re-render.
Difference between React 18 and earlier versions
In earlier versions of React, state updates are batched only for browser events. For example, if we call setCount
and setCount2
in a setTimeout
callback, React will not batch the state updates.
MultipleUpdates.jsx
import React, { useState } from "react";
function MultipleUpdates() {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
function handleClick() {
setTimeout(() => {
setCount((state) => state + 1);
setCount2((state) => state + 1);
}, 1000);
}
return (
<div>
<p>
Count: {count} / {count2}
</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
In React 18, state updates are batched for all updates, including setTimeout
and setIntevals
callbacks, event handlers, asynchronous code etc.
How to stop batching
If you want to stop batching, you can use ReactDOM.flushSync
to flush all pending state updates.
MultipleUpdates.jsx
import React, { useState, flushSync } from "react";
function MultipleUpdates() {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
function handleClick() {
setTimeout(() => {
flushSync(() => {
setCount((state) => state + 1);
// it forces React to render here
});
setCount2((state) => state + 1);
}, 1000);
}
return (
<div>
<p>
Count: {count} / {count2}
</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}