preface

A few months ago, I was lucky to do several projects with some friends. I have always known that setState of React is asynchronous and how to use setState correctly. Until I did the project with some friends mentioned above, one of them asked me that he modified a state with setState. Then I realized that setState is an asynchronous method and I forgot to tell them about it. Maybe I was so used to it that I thought it was too natural for me, which is why I planned to write this article

scenario

The scenario where setState is still the old value after using setState looks like this:

import React, { PureComponent } from 'react';

class Demo extends PureComponent {

  state = {
    count: 0
  }

  click = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1
    });
    console.log(this.state.count);

  }

  render() {
    const { count } = this.state;

    return (
      <div>
        <button onClick={this.click}>+1</button>
        <div>{count}</div>
      </div>
    );
  }
}

export default Demo;
Copy the code

Since setState is asynchronous, if we call setState and print state, we will always get the same state as before

There are two general solutions

Method 1: callback functions

Let’s change the setState code above to something like this:

this.setState( { count: count + 1 }, () => { console.log(this.state.count); });Copy the code

At this point, the output state is the modified value

Method 2: componentDidUpdate

Another method is to use the componentDidUpdate lifecycle method, which is executed after the component has been mounted to the DOM tree and the component has been re-rendered. The code looks like this:

import React, { PureComponent } from 'react';

class Demo extends PureComponent {

  state = {
    count: 0
  }

  componentDidUpdate() {
    const { count } = this.state;
    console.log(count);
  }

  click = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1
    });
  }

  render() {
    const { count } = this.state;

    return (
      <div>
        <button onClick={this.click}>+1</button>
        <div>{count}</div>
      </div>
    );
  }
}

export default Demo;
Copy the code

After I solved this problem for him, I started thinking about it: why is setState asynchronous?

Why is setState asynchronous

For performance and experience reasons, imagine if we needed to update multiple states:

import React, { PureComponent } from 'react';
import Comp1 from '@/components/Comp1';
import Comp2 from '@/components/Comp2';
import Comp3 from '@/components/Comp3';

class Demo extends PureComponent {

  state = {
    _1: 1,
    _2: 2,
    _3: 3
  }

  set1 = () => {
    const { _1 } = this.state;
    this.setState({
      _1: _1 + 1
    });
  }

  set2 = () => {
    const { _2 } = this.state;
    this.setState({
      _2: _2 + 1
    });
  }

  set3 = () => {
    const { _3 } = this.state;
    this.setState({
      _3: _3 + 1
    });
  }

  render() {

    return (
      <div>
        <Comp1 click={this.set1} />
        <Comp2 click={this.set2} />
        <Comp3 click={this.set3} />
      </div>
    );
  }
}

export default Demo;
Copy the code

In this case, setState is called. If it is synchronous, the program will block. React flusher updates together and performs a batch to avoid blocking

Assuming that the user is doing some interaction, such as input, the asynchronous operation does not block the user’s revenue behavior, but rather delays the update rendering, which makes the experience better

At the same time also, of course, this is my personal experience, is the result of recently completed a big data visualization of the project, is a data processing flow visualization show larger projects, this project be animation and data processing, due to a page, there is no switching, routing data is false data at the same time, So instead of using redux, you use state directly, and there’s a lot of user interaction, and the program responds to that interaction and updates the interface accordingly, and then there’s a lot of setState, and if setState is synchronous, So when the calculation and animation process is running, the user and the program interact with the program update interface, the update action will make the program block, at this time the animation and number calculation will stop, that is in trouble

Of course, this is just my personal opinion, but feel free to share it with me in the comments section, along with an explanation in the official documentation and a discussion on Github

reference

  1. When is setState asynchronous?

  2. RFClarification: why is setState asynchronous?