Automatic Batching is a major performance optimization introduced in React 18. It groups multiple state updates into a single re-render cycle, even when those updates occur inside promises, setTimeout, or native event handlers.
onClick).In React 18, regardless of where you trigger state changes, React waits until the end of the event loop tick to update the view.
// React 17 Behavior (Legacy)
setTimeout(() => {
setCount(c => c + 1); // Triggers Render 1
setFlag(f => !f); // Triggers Render 2
}, 1000);
// React 18 Behavior (Automatic Batching)
setTimeout(() => {
setCount(c => c + 1); // ...waits
setFlag(f => !f); // ...waits
// React renders ONCE here
}, 1000);
Here is a complete component demonstrating batching inside an asynchronous setTimeout callback.
// AutoBatchDemo.jsx
import React, { useState } from "react";
function AutoBatchDemo() {
const [count, setCount] = useState(0);
const [message, setMessage] = useState("Ready");
console.log("Rendered!"); // Checks how many times we render
const handleAsyncUpdate = () => {
// In React 17, this setTimeout would cause 2 renders
// In React 18, this causes only 1 render
setTimeout(() => {
setCount((c) => c + 1);
setMessage("Updated inside setTimeout");
}, 1000);
};
return (
<div>
<h4>Count: {count}</h4>
<p>Message: {message}</p>
<button onClick={handleAsyncUpdate}>
Update Asynchronously
</button>
</div>
);
}
export default AutoBatchDemo;
When you click the button:
Visualizing how React groups updates:
Click the buttons below to simulate how React handles state updates inside a setTimeout.
createRoot.flushSync.fetch().then() block.console.log('Render') in the component body.