Explain why React batches multiple state updates into a single render for performance, how automatic batching works (especially in React 18), and in which situations batching does not apply or can be disabled.
Why does React batch state updates? When does it not batch?
Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.
Short answer
React batches state updates to avoid unnecessary re-renders. If multiple state updates happen during the same logical event, React groups them and performs one render instead of many.
The first-principles reason
Rendering is expensive. Reconciliation + DOM updates cost time. If React re-rendered after every setState, a single click handler could trigger 3–5 renders in a row.
Batching turns this:
"Render → update → render → update → render"
into this:
"Update → update → update → render once".
function Counter() {
const [a, setA] = useState(0);
const [b, setB] = useState(0);
const onClick = () => {
setA(a + 1);
setB(b + 1);
// ✅ React batches these into ONE render
};
console.log('render');
return <button onClick={onClick}>Click</button>;
}
What batching guarantees
Within the same event or task, React waits until your logic finishes, then renders once using the final state.
Without batching | With batching | Why it matters |
|---|---|---|
Multiple renders per event | Single render per event | Much better performance |
Wasted reconciliation work | Minimal reconciliation | Scales better in large apps |
More layout/paint work | Fewer DOM commits | Smoother UI |
React 18: Automatic batching
Before React 18, batching only happened in React event handlers. In React 18+, batching happens almost everywhere:
• timeouts
• promises
• native event handlers
• async callbacks
setTimeout(() => {
setA(a + 1);
setB(b + 1);
// ✅ React 18 batches these too
}, 1000);
But when does React NOT batch?
Case | Does it batch? | Why |
|---|---|---|
Different ticks / separate tasks | ❌ No | They are not part of the same batch window |
Using flushSync | ❌ No (forces sync render) | You explicitly tell React to render immediately |
Legacy React (<18) async callbacks | ❌ No | Batching only existed in React events |
import { flushSync } from 'react-dom';
flushSync(() => {
setA(1);
});
// 👆 Forces immediate render here
setB(2);
// 👆 Causes another render
Important pitfall: stale state with non-functional updates
Because updates are batched, this is WRONG:
setCount(count + 1);
setCount(count + 1); // ❌ still only +1
Because both updates read the same snapshot. The correct version is:
setCount(c => c + 1);
setCount(c => c + 1); // ✅ +2
Interview framing
Say it like this:
"React batches state updates to minimize renders and improve performance. In React 18, batching is automatic across events, promises, and timeouts. It only stops batching when you cross async boundaries or explicitly force sync rendering with flushSync."
React batches state updates to reduce unnecessary renders and DOM work. In React 18, batching is automatic in most async and sync contexts. It does not batch across separate tasks or when you explicitly force synchronous rendering with flushSync. Because of batching, functional state updates are often required to avoid stale values.