Under The Hood
frontend react React 18 / 19

Automatic Batching: Microtask Grouping Across Asynchronous Boundaries

Last updated
Prerequisites:
React useState / state update queues
JavaScript Event Loop and Microtask Queue
  • react
  • automatic-batching
  • event-loop
  • microtasks
  • react-18
  • performance

Read at your depth

The practical view

In React 18+, **Automatic Batching** groups multiple state updates (`setState`) into a single re-render pass, regardless of where the updates originate. In React 17, batching only worked inside native React event handlers. In React 18+, updates inside `fetch()` callbacks, `setTimeout`, `Promise.then`, or native DOM listeners are automatically batched together into one render.

The same idea in other frameworks

react equivalent
Automatic batching via microtask update queues / `flushSync()` escape hatch.

Legacy vs modern

Un-batched Async Updates (React 17) vs Automatic Batching (React 18+)

In React 17, updating state inside a fetch callback triggered 2 separate renders; React 18+ automatically batches them into 1 render.

before → after
Double Render in Async Callbacks (React 17)
fetch().then(() => { setCount(c => c+1); setFlag(f => !f); }); // ❌ 2 re-renders in React 17
Automatic Batching (React 18+)
fetch().then(() => { setCount(c => c+1); setFlag(f => !f); }); // ✅ Exactly 1 re-render

Interview gotchas

Context

Interviewers test your knowledge of escape hatches like `flushSync`.

The mechanical answer

Wrap the state update in `ReactDOM.flushSync()`: `flushSync(() => { setCount(c => c + 1); });`. `flushSync` forces React to immediately execute the render and commit phases synchronously before returning, which is useful when reading DOM layout measurements (like scroll position) immediately after a state change.

Trap

`flushSync` degrades rendering performance significantly; only use it when strictly necessary for immediate DOM geometry calculation.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.