When I was writing React, I found that setstate would not be updated immediately after several times, so I decided that setstate was an asynchronous method. However, I did not ask myself why setstate was asynchronous until ONE day, when I wanted to get the updated state immediately to pass another method. To be precise, setState is asynchronous where the React internals can detect it; In places where React cannot detect, such as setInterval and setTimeout, setState is updated synchronously.

1. SetState executes batch overrides during react lifecycle and compositing events

React encapsulates a set of event mechanisms to address cross-platform and compatibility issues, and agents native events such as onClick and onChange in JSX are synthesized events

For example 🌰 will extract a single pass setState Object when multiple setState calls are encountered, just like object. assign Object merges. Similarly, the last key overwrites the previous key

const a = {name : 'kong', age : '17'}
const b = {name : 'fang', sex : 'men'}
Object.assign({}, a, b);
//{name : 'fang', age : '17', sex : 'men'}
Copy the code

2. Setstate in native events, setTimeout and setInterval, asynchronous operations such as promise, the state will be an update

When setTimeout is executed, the finally main process block is executed first. When finally is executed, isBatchingUpdates are changed to false. The requestWork would have the same expirationTime === Sync if branch as the native event. If the requestWork would have the same expirationTime === Sync if branch as the native event. The requestWork would have the same expirationTime === Sync if branch as the native event.

3. SetState batch update process

The React lifecycle and compositing events are preceded and followed by the pre hook and post hook, respectively. The Pre hook calls the batchedUpdate method to set isBatchingUpdates to true to enable batch updates. The POST hook will set isBatchingUpdates to false

First, setState method

ReactComponent.prototype.setState = function(partialState, callback) {// willsetThe State affairs in the queue for this. The updater. EnqueueSetState (this, partialState);if (callback) {
    this.updater.enqueueCallback(this, callback, 'setState'); }};Copy the code

The partialState here produces a new state that is merged with the old state in the form of object.assgine ().

Second, the enqueueSetState

 enqueueSetState: function(publicInstance, PartialState) {/ / get the current component instance var internalInstance = getInternalInstanceReadyForUpdate (publicInstance,'setState'); / / will update the state into an array of var queue. = internalInstance _pendingStateQueue | | (internalInstance. _pendingStateQueue = []); queue.push(partialState); // The component instance to be updated is also placed in a queue enqueueUpdate(internalInstance); }Copy the code

Third, enqueueUpdate

functionEnqueueUpdate (Component) {// Update state transactions are processed if components are not in the batch creation/update phaseif(! batchingStrategy.isBatchingUpdates) { batchingStrategy.batchedUpdates(enqueueUpdate, component);return; } // If you are in the process of batch creating/updating components, place the current component in the dirtyComponents array dirtyComponents.push(Component); }Copy the code

If the isBatchingUpdates variable is set to true, the batch update branch will be executed, and the setState update will be queued. After the synchronization code is completed, the state update in the queue will be executed. If isBatchingUpdates is true, the current component (the one that called setState) is put in the dirtyComponents array; Otherwise batchUpdate all queue updates

Four, batchingStrategy

Var ReactDefaultBatchingStrategy = {/ / used to mark is currently out of the batch update isBatchingUpdates:false// When this method is called, batchedUpdates will be batch updated:function (callback, a, b, c, d, e) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true; // If the current transaction is in the process of updating, callback, enqueueUpdate, is calledif (alreadyBatchingUpdates) {
      return callback(a, b, c, d, e);
    } else{// Otherwise, the update transaction is performedreturntransaction.perform(callback, null, a, b, c, d, e); }}};Copy the code

Five, the transaction

BatchedUpdates initiates a transaction.perform() transaction. AnyMethod in this transaction flow is runBatchedUpdates, which updates the component state and runs through the component lifecycle. When componentWillMount, the accumulated states in the A state queue are processed in sequence. Wrapper close, loop through dirtyComponents and execute Transaction. Perform (runBatchedUpdates, NULL, Transaction); ", so A is picked up and starts to run through the transaction flow until the last component in the dirtyComponents has run through the process and all components have been uniformly updated.Copy the code

4. Finally, a quiz

(1)

(2) a few days ago, I suddenly wrote out a self-uncertain execution order 😃 (write bug…)
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false}}componentWillMountOnClick = () => {setTimeout(() => {this.setState({ loading: true }, () => {console.log('1-setState'); })}, 4000) new Promise(resolve => { this.setState({ loading:false }, () => {console.log('3-setState'); }); console.log('2');
      resolve(4);

    })
    .then((res) => {
      this.setState({ loading: false }, () => {console.log('2-setState'); }); console.log(res,'////res');
    });
    console.log('1');
  }

  render() {
    return <Button type="primary"Loading = {this. State. Loading} onClick = {this. The onClick} >. </Button>; }}export default App;
Copy the code

The source for the then method in promise wraps the incoming method in a setTimeout, In order to execute the then method immediately and return the promise to do the recursion, setstate is synchronized in this environment so 2-setstate is earlier than console.log(res, ‘////res’) on the following line;

Interested students can study I comb and annotate the promise source github.com/xinqiymsz/p…