State Batching
State Batching
React optimizes performance by batching multiple state updates into a single re-render. Instead of re-rendering the component every time a state setter is called, React waits until all the code in the event handler has finished executing before processing the state updates and triggering a re-render.
Example of Batching
function ProfileForm() {
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const [isSubmitting, setIsSubmitting] = useState(false);
function handleSubmit() {
// These three state updates are BATCHED together.
// React will only re-render the component ONCE, not three times.
setName('John');
setAge(30);
setIsSubmitting(true);
}
// ...
}
This is similar to a waiter taking an entire order at a restaurant before running to the kitchen, rather than running back and forth for the drink, then the appetizer, then the main course.
Automatic Batching in React 18
Prior to React 18, React only batched updates that occurred inside React event handlers (like onClick or onChange). Updates inside asynchronous callbacks (like setTimeout, fetch promises, or native event listeners) were not batched, resulting in multiple re-renders.
// React 17 behavior:
fetch('/api/data').then(() => {
setName('John'); // Re-render 1
setAge(30); // Re-render 2
});
In React 18 and newer, Automatic Batching was introduced. React now batches all state updates, regardless of where they happen (promises, timeouts, native event handlers, etc.).
// React 18 behavior:
fetch('/api/data').then(() => {
setName('John');
setAge(30);
}); // Re-renders ONCE at the end of the callback!
Opting out of Batching (Rare)
In very rare cases where you explicitly need the DOM to update synchronously between state changes (e.g., you need to read a DOM measurement after one state change, but before another), you can use flushSync from react-dom.
import { flushSync } from 'react-dom';
function handleClick() {
flushSync(() => {
setCounter(c => c + 1);
});
// React has updated the DOM here synchronously
flushSync(() => {
setFlag(f => !f);
});
// React has updated the DOM here synchronously again
}
Note: You should almost never need to use flushSync in standard application development.
Interview Questions
Q: What is Automatic State Batching, and how did it change in React 18?
A: State batching is when React groups multiple setState calls into a single re-render to maximize performance. Before React 18, React only batched updates inside standard React event handlers (like onClick). In React 18, React automatically batches state updates everywhere, including inside Promises, setTimeout, and native event listeners.