skip to Main Content
import { Component } from "react";

export class SimpleButton extends Component {
   constructor(props) {
      super(props);
      this.state = {
         counter: 0,
      }
   }
   
   render() {
      return (
         <button onClick={this.handleClick}>
            ...
         </button>
      )
   }
   // ...

   handleClick = () => { 
      for (let i = 0; i < 5; i++) {
         this.setState({ counter: this.state.counter + 1});  // multiple changes to the same state data property are ignored and only the most recent vlaue is applied
      }                                                      // so the whole for loop is like a single `this.setState({ counter: this.state.counter + 1});`
   }
}

I was told that multiple setState changes to the same state data property are ignored and only the most recent vlaue is applied, so the whole loop above is like a single this.setState({ counter: this.state.counter + 1});

But I’m wondering why React does it in this way? isn’t that setState() just enqueues an unit of work in a "queue", and later React dequeues each work from the queue and applies the change, so even there is 5 times of setState() call, there will be 5 unit of works in the queue, then React can just dequeue and execute each one, isn’t this design is more straightforward and bugs-less?

2

Answers


  1. From React – Component State:

    Passing an update function allows you to access the current state value inside the updater. Since setState calls are batched, this lets you chain updates and ensure they build on top of each other instead of conflicting:

    incrementCount() {
      this.setState((state) => {
        // Important: read `state` instead of `this.state` when updating.
        return {count: state.count + 1}
      });
    }
    
    handleSomething() {
      // Let's say `this.state.count` starts at 0.
      this.incrementCount();
      this.incrementCount();
      this.incrementCount();
    
      // If you read `this.state.count` now, it would still be 0.
      // But when React re-renders the component, it will be 3.
    }
    
    Login or Signup to reply.
  2. React batches state updates for performance reasons. When you call setState() multiple times in a synchronous manner (like in your for loop), React batches these updates and only applies the final state value. This behavior is to prevent unnecessary re-renders of the component and improve performance.

    By batching state updates, React ensures that the component only renders once with the final state value after all the state updates are processed. This way, it avoids unnecessary intermediate renders, which can be resource-intensive and slow down the application.

    In summary, React batches state updates to optimize rendering performance by applying only the final state value, thus reducing the number of component re-renders.

    here’s the modified code to demonstrate the behaviour of batching state updates in React:

    import React, { Component } from "react";
    
    export class SimpleButton extends Component {
      constructor(props) {
        super(props);
        this.state = {
          counter: 0,
        };
      }
    
      handleClick = () => {
        // setState calls are batched together
        for (let i = 0; i < 5; i++) {
          this.setState({ counter: this.state.counter + 1 });
        }
      };
    
      render() {
        return (
          <div>
            <p>Counter: {this.state.counter}</p>
            <button onClick={this.handleClick}>Increment</button>
          </div>
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search