React Curriculum

State Updates & React 18 Automatic Batching

Medium100% Free~25 mins#react#batching#react18#automatic-batching#flushsync#event-loop
Interview Answer (30-Second Summary)

Batching groups multiple state updates into a single re-render to optimize performance. In React 18+, automatic batching batches updates everywhere—including promises, setTimeout, and native event handlers—unless explicitly opted out via flushSync.

Key Learning Objectives
✓

Understand the performance rationale behind batching multiple state updates.

✓

Explain how React 18 automatic batching differs from React 17 synthetic-event-only batching.

✓

Identify how promises, setTimeout, and fetch callbacks are batched in React 18.

✓

Use flushSync responsibly when synchronous DOM measurement is required.

The Interview Problem & Context

What is logged to the console when simulating state batching inside an asynchronous Promise in React 17 vs React 18 vs flushSync?

1// Simulating render counts for 2 consecutive state updates inside an async callback
2function simulateBatching() {
3 // React 17: Async callbacks (setTimeout, Promise) did NOT batch -> 2 renders
4 const react17AsyncRenders = 2;
5
6 // React 18: Automatic Batching groups async state updates -> 1 render
7 const react18AsyncRenders = 1;
8
9 // React 18 flushSync: Forces immediate synchronous DOM flush -> 1 render per call -> 2 renders
10 const flushSyncRenders = 2;
11
12 return `${react18AsyncRenders} ${react18AsyncRenders} ${flushSyncRenders}`;
13}
14
15console.log(simulateBatching());
Predict Console & Render Output
A

1 1 2

B

2 2 2

C

1 2 1

D

0 1 2

Execution Trace
Step 1 of 3 (Line 4)

React 18 batches async state updates into a single render pass.

Component / Call Stack
simulateBatching()
Hook State & Scope
react18AsyncRenders:1
Console Output(No console logs emitted)
Deep Architectural Explanation

React 18 Automatic Batching

Batching is when React groups multiple state updates into a single re-render pass for better performance.

The History: React 17 vs React 18

  • React 17 & Older: Only batched updates inside React event handlers (like onClick). Updates inside setTimeout, Promise.then, fetch callbacks, or native event listeners triggered separate renders for each setState call.
  • React 18: Introduces Automatic Batching. Updates inside promises, timeouts, and native event handlers are all automatically batched into a single render pass out-of-the-box when using createRoot.

Opting Out with flushSync

If you need to synchronously read from the DOM immediately after updating state (e.g., scroll a container to a newly added element), React provides flushSync from react-dom:

tsx
import { flushSync } from 'react-dom';

flushSync(() => {
  setItems(prev => [...prev, newItem]);
});
// The DOM has been updated synchronously!
listRef.current.scrollTop = listRef.current.scrollHeight;

Note: flushSync hurts performance because it forces a synchronous render and browser layout pass. Use it sparingly.

Common Interview Traps & Pitfalls
✕

Assuming React 17 batched updates inside fetch() callbacks.

✕

Using flushSync everywhere out of fear that state will not update in time.

✕

Relying on state updates occurring synchronously in unit tests without act().

Senior Interviewer Follow-Up Probes
?

How does React 18 know which updates belong to the same batch in microtask queues?

?

Why does ReactDOM.createRoot enable automatic batching, while legacy ReactDOM.render does not?

?

How does flushSync interact with Concurrent React transitions?

Frequently Asked Interview Questions
What is automatic batching in React 18?

Automatic batching groups multiple state updates into a single re-render pass regardless of where they originate—including promises, setTimeout, and native event listeners.

In React 17, batching was tied to the SyntheticEvent call stack. Once execution yielded to the browser event loop (such as in an async callback), React lost execution context and had to render immediately.

Only when you must immediately measure or manipulate the DOM based on new state, such as scrolling to the bottom of a chat window or measuring an element height before an animation.

No. Automatic batching is an exclusive feature of the React 18 createRoot API; applications using the legacy ReactDOM.render retain React 17 batching behavior.

Yes. If multiple components have their state updated within the same event or asynchronous callback, React 18 batches all of them into a single coordinated re-render pass.