preface


When we use setState in React, we know that it’s not always asynchronous, it can be synchronous. We also know that setState is used asynchronously to improve performance by accumulating updates, batch processing, and reducing the number of calls.

setState API


setState(updater, [callback])
Copy the code
updater
(state, props) => stateChange
Copy the code

The updater function is guaranteed to receive the latest state and props. The updater’s return value is lightly merged with state.

callback

The second argument to setState() is an optional callback function that will be executed after setState has merged and rerendered the components. In general, we recommend using componentDidUpdate() instead.

asynchronous


SetState queues changes to the component state and notifies React that the component and its children need to be rerendered with the updated state. For better performance, setState does not update immediately, but uses batch deferred updates.

Take a look at a few examples of asynchron, these are examples of code that often appear in interviews (source testing)

class Test extends Component {
  state = {
    count: 0
  };

  componentDidMount() {
    this.setState({
        count: 1
      }, () = > {
        console.log(this.state.count); / / 1});console.log(this.state.count); / / 0
  }
  render(){}}Copy the code
class Test extends Component {
  state = {
    count: 0
  };

  componentDidMount() {
    this.setState(
      {
        count: this.state.count + 1
      },
      () = > {
        console.log(this.state.count); / / 1});this.setState(
      {
        count: this.state.count + 1 // The count is still 0, and you don't get the updated count
      },
      () = > {
        console.log(this.state.count); / / 1}); }render(){}}Copy the code
class Test extends React.Component {
  state = {
    count: 0
  };

  componentDidMount() {
    this.setState(
      (preState) = > {
        console.log(preState.count); / / 0
        return {
          count: preState.count + 1
        };
      },
      () = > {
        console.log(this.state.count); / / 2});this.setState(
      (preState) = > {
        console.log(preState.count); / / 1
        return {
          count: preState.count + 1
        };
      },
      () = > {
        console.log(this.state.count); / / 2}); }render() {
    return <div>1</div>; }}Copy the code

When the setState function is called, the current operation will be put into the queue. React merges state data according to the content, executes the callback one by one after completion, updates the required DOM according to the result, and triggers the rendering. This is an asynchronous approach, which is said to be asynchronous in order to accumulate updates, batch processing, reduce rendering times, and improve performance.

Can’t synchronization accumulate updates and batch them


Here we actually change the Angle to think, can’t synchronization accumulate updates, batch processing? Can’t synchronization reduce render times and improve performance?

In fact, I am not the only one who has doubts about this issue. Some leaders have already raised this issue on Issues long ago:

Of course, in the following Issues, Gaearon replied to this question:

The answer is long and summarizes two aspects:

1. Be consistent

If you change to the synchronized update method, setState is synchronized, but props is not.

2. Enable concurrent updates for subsequent schema upgrades

In order to complete a render, React updates the data source to assign a different priority when the setState is triggered. These data sources include: event callback handles, animation effects, etc., and are processed concurrently according to priority to improve rendering performance.