What is batching in React?
What batching is
Batching is a mechanism where React combines several setState calls into one shared render, so the component re-renders only once, instead of after every state change.
Example without batching (in theory)
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
};
console.log('render', count);
return <button onClick={handleClick}>{count}</button>;
}If batching did not exist, React would do:
setState 1 → render
setState 2 → render
setState 3 → renderThat would mean three re-renders in a row, slow and inefficient.
With batching (how React actually works)
React groups all these updates into one batch:
setState 1
setState 2
setState 3
↓
1 shared renderSo the component re-renders only once.
What happens under the hood
React does not update state immediately when setState is called.
It:
- Puts the update into an update queue;
- Waits until all synchronous events finish processing (for example,
onClick); - Then applies all accumulated updates in one batch, recomputes state, and triggers one render.
Example (a visible result)
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(c => c + 1);
setCount(c => c + 1);
setCount(c => c + 1);
};
console.log('render');
return <button onClick={handleClick}>{count}</button>;
}After one click:
- All three
setCountcalls run; countincreases by 3;- The component re-renders once.
When batching works
With React 18, always, by default (previously it only worked inside React events, and now it works in any asynchronous context too).
Example - React 17 (the old behavior):
useEffect(() => {
setCount(c => c + 1);
setFlag(true);
});React 17: performs two separate renders,
because the updates happen asynchronously (inside useEffect).
React 18: batching is enabled even for async code (fetch, setTimeout, Promise).
Example (React 18 - automatic batching)
setTimeout(() => {
setCount(c => c + 1);
setFlag(f => !f);
}, 1000);React 17: → two renders (batching did not work outside React events). React 18: → one render (both operations are grouped automatically).
Batching can be disabled manually (rarely)
Sometimes you need to update the UI immediately (for example, in tests or animations).
There is flushSync for this:
import { flushSync } from 'react-dom';
flushSync(() => setCount(c => c + 1));
flushSync(() => setFlag(true));Each operation runs as a separate render, React will not group them.
Why batching matters
| Benefit | What it gives |
|---|---|
| Fewer re-renders | React does not update the component after every little thing |
| More predictable behavior | All updates are applied "atomically" |
| Performance | Less diffing, reconciliation, and DOM work |
| Consistency | State is recomputed from current data |
How batching relates to concurrent rendering (React 18)
-
React can now defer less important updates;
-
batching helps React group and prioritize updates;
-
it is the foundation for
startTransition()anduseDeferredValue():javascriptstartTransition(() => { setSearchQuery(value); // low-priority update });
Summary
| What batching is | How it works |
|---|---|
| A mechanism for grouping state updates | Several setState calls trigger one render |
| Enabled everywhere in React 18 | Even in promises, async/await, setTimeout |
| Improves performance | Fewer unnecessary re-renders |
Can be disabled via flushSync() | For urgent updates |
| Foundation of concurrent rendering | React can optimize the render stream |
In simple terms:
batching is when React waits until you "press Enter" after a series of
setStatecalls, and does one shared render instead of a dozen small ones.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.