Understanding React batchedUpdates and setState Performance Optimization

This article explains how React (pre‑16.8) batches multiple setState calls using batchedUpdates, demonstrates the internal mechanism with source‑level debugging, shows code examples including setTimeout edge cases, and summarizes the key steps that enable the framework’s performance optimization.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Understanding React batchedUpdates and setState Performance Optimization

Before React 16.8, calling setState multiple times triggers an internal performance optimization called batch updates. The article examines how this optimization works in React 15, focusing on the batchedUpdates mechanism that merges several state updates into a single React task.

The batchedUpdates function is automatically invoked by event handlers; it groups successive setState calls so that they are applied together during one render cycle, reducing unnecessary re‑renders.

Example component BatchedDemo demonstrates the behavior:

import React from 'react';
import { unstable_batchedUpdates as batchedUpdates } from 'react-dom';

export default class BatchedDemo extends React.Component {
  state = { number: 0 };

  handleClick = () => {
    // event handler already runs inside batchedUpdates
    // this.countNumber();
  };

  countNumber() {
    const num = this.state.number;
    this.setState({ number: num + 1 });
    console.log(this.state.number); // 0 – state not updated yet
    this.setState({ number: num + 2 });
    console.log(this.state.number); // 0
    this.setState({ number: num + 3 });
    console.log(this.state.number); // 0
  }

  render() {
    return <button onClick={this.handleClick}>Num: {this.state.number}</button>;
  }
}

Debugging the React source reveals that when isBatchingUpdates is set to true, the function requestWork returns early, skipping performSyncWork. The pending updates are stored in the queue via enqueueSetState, but the state is not applied until batching ends.

The core of the batching logic is shown in the React source:

function batchedUpdates<A, R>(fn: (a: A) => R, a: A): R {
  const previousIsBatchingUpdates = isBatchingUpdates;
  isBatchingUpdates = true;
  try {
    return fn(a); // actual event handler runs here
  } finally {
    isBatchingUpdates = previousIsBatchingUpdates;
    if (!isBatchingUpdates && !isRendering) {
      performSyncWork(); // apply all queued updates at once
    }
  }
}

When setTimeout is used, it creates a macro‑task where isBatchingUpdates starts as false. Consequently, state updates inside the timeout are not batched, and each setState triggers a separate render.

handleClick = () => {
  // setTimeout runs without batchedUpdates, isBatchingUpdates stays false
  setTimeout(() => {
    this.countNumber();
  }, 0);
};

To force batching inside a timeout, the article shows wrapping the call with batchedUpdates:

handleClick = () => {
  setTimeout(() => {
    batchedUpdates(() => this.countNumber());
  }, 0);
};

In summary, React’s batch update process relies on the temporary variable previousIsBatchingUpdates to remember the prior batching state, sets isBatchingUpdates to true during the event, queues all setState calls, and finally restores the original flag and runs performSyncWork to apply the updates efficiently.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

FrontendperformanceJavaScriptReActbatchedUpdatessetState
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.