⚛️ React Q73 / 113

What is automatic batching?

AI-Powered Answer ✓ Answered

Automatic batching is a performance optimization introduced in React 18 that groups multiple state updates into a single re-render, even for updates originating from different events or asynchronous operations. This significantly reduces the number of re-renders, leading to better application performance.

What is Batching?

Batching in React refers to the process of grouping multiple state updates (e.g., setState, useState updates) into a single re-render cycle. Instead of re-rendering the component for each individual state update, React waits until all updates are processed within a specific context and then performs a single, consolidated re-render.

Why is Batching Important?

  • Performance Improvement: By reducing the number of re-renders, React saves computational resources, leading to faster UI updates and a smoother user experience.
  • Prevents Stale Intermediate States: It ensures that components only re-render with the final, consistent state after all synchronous updates have been applied, preventing the UI from displaying temporary, inconsistent states.

Automatic Batching (React 18+)

With React 18 and the createRoot API, automatic batching is enabled by default. This means that all state updates, regardless of where they originate (e.g., event handlers, promises, setTimeout callbacks, native event handlers), will be automatically batched together into a single re-render. This is a significant improvement over previous versions of React, where batching only occurred within browser event handlers.

For example, if you update two different state variables sequentially within a setTimeout callback, React 18 will batch both updates and perform only one re-render. In older React versions, this would have resulted in two separate re-renders.

Before React 18 (Legacy Batching)

Prior to React 18, batching only worked for updates *inside* browser event handlers. State updates triggered outside of these contexts (e.g., within setTimeout, Promise.then(), or custom event handlers) would cause an immediate re-render for each update. This often led to unnecessary re-renders and potential performance issues.

jsx
function MyComponent() {
  const [count, setCount] = React.useState(0);
  const [flag, setFlag] = React.useState(false);

  function handleClick() {
    // Before React 18, these would *not* be batched if outside a browser event handler.
    // In React 18, these *are* batched automatically.
    setTimeout(() => {
      setCount(c => c + 1); // Triggers re-render (legacy)
      setFlag(f => !f);    // Triggers another re-render (legacy)
    }, 0);
  }

  return (
    <button onClick={handleClick}>
      Count: {count}, Flag: {String(flag)}
    </button>
  );
}

Opting Out of Automatic Batching

While automatic batching is generally beneficial, there might be rare cases where you need an immediate re-render after a specific state update (e.g., to measure DOM layout changes immediately after an update). For these scenarios, React provides ReactDOM.flushSync.

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

function MyComponent() {
  const [count, setCount] = React.useState(0);
  const [flag, setFlag] = React.useState(false);

  function handleClick() {
    flushSync(() => {
      setCount(c => c + 1);
    });
    // The component will re-render immediately after setCount finishes.
    console.log('Count updated and rendered:', count);

    setFlag(f => !f); // This will be batched normally with other updates.
  }

  return (
    <button onClick={handleClick}>
      Count: {count}, Flag: {String(flag)}
    </button>
  );
}