Update the state setState

The React type component update page can access the this.setState(stateChange, callback) method through the component instance.

  1. setStateFunction that takes two arguments: to update the state and to re-invoke the render of the current component
    • The first argument: isobjectorfunctionIn the framework, the object itself or the return value of a function call is similar to the current stateObject.assign()merge.
      / / object
      this.setState({
        counter: this.state.counter + this.props.increment,
      })
      
      / / function
      this.setState((preState, props) = > ({
        counter: preState.counter + props.increment
      }))
      Copy the code
    • The second parameter: isThe callback functionThe second parameter callback is executed after the state data merge operation is complete and before the component’s render function is called.
      render() {
          let { count } = this.state
          return <div>
              <button onClick={()= >{this.setState({count: count + 1}, () => {console.log(' change before count', count); Console. log(' count after change ', this.state.count); })}}> point I increment 1</button>The current counter is {count}</div>
      }
      Copy the code
  2. setState() The calling code itself isSynchronous executionBut both the merge operation and the call to render function areAsynchronous execution(microtasks). So be careful, in the code that executes synchronously, the following code, after two values, the merge and re-render components are performed, so both values are the same.
    state = { count: 0 }
    
    // ❌ The value of this.state.count is the same as the value of 0 + 1 in the first call
    handle = () = > {
        this.setState({ count: this.state.count + 1 }, () = >{... })this.setState({ count: this.state.count + 1 }, () = >{... })}// ✅ write the first parameter of setState as a function to receive the value of each update
    handle = () = > {
        this.setState(preState= > ({ count: preState.count + 1 }), () = >{... })this.setState(preState= > ({ count: preState.count + 1 }), () = >{... })}Copy the code

SetState Execution flow

Did not read the source code or analysis of the source code article verification, pure self-testing, in line with the test results

  1. When the first argument to the setState function isobjectWhen:
    1. Execute synchronization code: setState function call, the first parameter object member value, register the following three asynchronous microtasks, continue to execute the following synchronization code
    2. Clear (execute) the microtasks in the current macro task:
      1. Perform the merge operation task to merge the first parameter object with the current state object (the state data is updated)
      2. The second parameter callback of setState is executed
      3. Execute the render function of the current component (view updated)
  2. When the first argument to the setState function isfunctionWhen:
    1. Execute synchronization code: the setState function call, with the first parameter function definition, registers the following four asynchronous microtasks to continue with the subsequent synchronization code
    2. Clear (execute) the microtasks in the current macro task:
      1. Execute the first argument function, get the return value object, and evaluate the member of the object
      2. Perform the merge operation task to merge the return value object with the current state object (the state data is updated)
      3. The second parameter callback of setState is executed
      4. Execute the render function of the current component (view updated)

SetXXX in useState Hook is the same as the setState function of the class component, except that: 1. SetXXX is not overloaded, only one parameter, no second parameter callback. 2. SetXXX update status is a replacement operation, not a merge operation

Multiple calls to merge render

React optimizes performance when the setState function is called multiple times.

  1. Call setState in synchronous code environment: In the normal React event flow, a class component executes setState multiple times or a function component executes setXXX multiple times in a useState and only calls the render again once. This is called merge render

    If the render is not merged, the component will have to be rerendered every time the setState update function is executed, resulting in an invalid render and a waste of time (because the last render overwrites all previous render effects).

    So React will group some set states that can be updated together, merge them, and render only one last time.

  2. Call setState in asynchronous code environment: Execute setState and setXXX in useState multiple times in asynchronous events such as setTimeout, promise. then, and call render on each execution

    SetTimeout is out of react’s control, and React cannot add transaction logic to the setTimeout callback code (unless React overrides setTimeout).

    When faced with setTimeout/setInterval/Promise. Then (fn)/fetch callback/XHR callback network, the react is unable to control.