Batching is when React groups multiple state updates into a single re-render for better performance.
For example, if you have two state updates inside of the same click event, React has always batched these into one re-render. If you run the following code, you’ll see that every time you click, React only performs a single render although you set the state twice:
function App() {
const [count, setCount] = useState(0);
const [loading, setLoading] = useState(false);
const handleClick = () => {
fetchData().then(() => {
// React 17 or earlier does NOT batch these updates
// These will be two different updates
setCount(c => c + 1); // 1st update and re-render
setLoading(l => !l); // 2nd update and re-render
});
}
return (
<div>
<button onClick={handleClick}>Next</button>
<h1 style={{ color: loading ? "blue" : "black" }}>
{count}
</h1>
</div>
);
}
In React 18, all updates will be automatically batched, no matter where they originate from.
This means that updates inside of timeouts, promises, native event handlers or any other event will batch the same way as updates inside of React events. We expect this to result in less work rendering, and therefore better performance in your applications by avoiding unnecessary re-renders and thus improve the performance.
How to opt out of batching?
flushSync is a method in React that allows you to force a synchronous update to a component. It can be used in cases where you need to update a component immediately, rather than waiting for the next render cycle. This can be useful for cases such as updating a component's state in response to a user interaction, or for doing some other type of imperative update.
Additionally, flushSync is not recommended to use in most cases, it's better to rely on React's built-in mechanism to handle updates. It's only recommended to use in cases where you need to update a component immediately, and the regular way of updating component is not working.
import { flushSync } from 'react-dom';
const handleClick = () => {
flushSync(() => {
setCounter(c => c + 1);
});
// 1st update and re-render
flushSync(() => {
setLoader(l => !l);
});
// 2nd update and re-render
}
Top comments (0)