React Automatic Batching
Automatic batching lets React group multiple state updates into fewer render passes, reducing unnecessary rendering work. In modern React, batching applies across more asynchronous contexts than it did in older React versions.
When several state setters run during the same update cycle, React can combine them before rendering. For example, calling `setCount` and `setFlag` in the same handler can produce one render rather than rendering once after each setter.
Batching changes how often React renders, not how state variables behave inside the current function. Multiple calls such as `setCount(count + 1)` can still use the same captured `count`; when updates depend on previous state, use the functional form `setCount(c => c + 1)`.
In React 18 and later, automatic batching is enabled with the modern `createRoot` API. It can batch updates from places such as event handlers, promises, timers, and native event callbacks. Older React versions had narrower batching behavior, especially outside React-managed events.
Batching is primarily a performance optimization. It does not mean that state updates are ignored or that React must immediately update the DOM after every setter. If code genuinely needs a synchronous DOM update, React provides `flushSync`, but it should be used sparingly because it can reduce batching benefits.
Key points
- React can combine multiple state updates into a single render.
- Functional state updates are important when successive updates depend on previous state.
- React 18 with `createRoot` extends automatic batching beyond traditional React event handlers.
- Batching reduces rendering work but does not make state setters immediately mutate the current state variable.
- `flushSync` can force synchronous processing when a specific integration requires it.
Interview questions
What is automatic batching in React?
Automatic batching means React groups multiple state updates so they can be processed with fewer renders. This avoids doing rendering work after every individual state setter. In modern React, batching covers more asynchronous situations than older React versions. It is mainly a performance optimization and does not mean state setters immediately change the current value.
Why should you use a functional state update when incrementing state multiple times?
A normal state expression such as `setCount(count + 1)` uses the `count` value captured by the current render. Multiple such calls can therefore calculate the same next value. A functional update such as `setCount(c => c + 1)` receives the pending previous state for that update. This lets multiple increments compose correctly.
How did automatic batching change in React 18?
React 18 expanded automatic batching when applications use the modern `createRoot` API. Updates originating from promises, timers, and other asynchronous callbacks can be batched rather than being limited primarily to React event handlers. This can reduce the number of render passes in applications with asynchronous state changes. Code relying on an immediate render between separate updates may need reconsideration.
Does batching mean React only runs one state update when several setters are called?
No. Batching groups the updates for rendering; it does not discard the individual updates. React processes the queued updates according to their ordering and update semantics. Functional updaters can therefore be applied sequentially and produce a cumulative result. The important distinction is that several state changes may be committed together rather than causing separate renders.
When would you use `flushSync`?
`flushSync` is an escape hatch for cases where an update must be processed synchronously, often when integrating with code that immediately reads the DOM after changing state. It forces React to flush updates within the callback instead of relying on normal batching behavior. Because this can increase rendering work and interfere with performance, it should not be treated as the default way to control state timing. The need for it should come from a concrete synchronization requirement.