setState and forceUpdate for React Source Resolution

1. enqueueSetState()
In non-asynchronous methods, no matter how many setStates are invoked, they are queued for updates after the last setState, and then a unified update is performed, as detailed in:
The mechanism of state batch processing for React.setState and Why is React.setState asynchronous?

Effect:
Create an update to the fiber object of the React node and queue the update object

Source code:

//update object obtained when classComponent is initialized
const classComponentUpdater = {
  isMounted,
  enqueueSetState(inst, payload, callback) {
    //inst is this passed in when this.setState is called
    //This is the classComponent instance

    //Get the fiber object through this
    //this._reactInternalFiber
    //this has its own property to store the fiber object called _reactInternalFiber
    const fiber = getInstance(inst);
    //Calculate the current time, not mentioned before
    const currentTime = requestCurrentTime();
    //Settings for asynchronous loading, not to mention yet
    const suspenseConfig = requestCurrentSuspenseConfig();
    //Calculate the expiration time of the fiber object
    const expirationTime = computeExpirationForFiber(
      currentTime,
      fiber,
      suspenseConfig,
    );
    //Create update object
    const update = createUpdate(expirationTime, suspenseConfig);
    //setState incoming object to update
    update.payload = payload;
    //Callback is the callback function for setState ({}, ()=>{})
    if (callback !== undefined && callback !== null) {
      if (__DEV__) {
        warnOnInvalidCallback(callback, 'setState');
      }
      update.callback = callback;
    }
    //Ignore for the moment
    if (revertPassiveEffectsChange) {
      flushPassiveEffects();
    }
    //update enrolled
    enqueueUpdate(fiber, update);
    //task scheduling
    scheduleWork(fiber, expirationTime);
  },
};

Resolution:
(1)getInstance

//getInstance
export function get(key) {
  return key._reactInternalFiber;
}

This is to get the _reactInternalFiber property of the target object, which is this in this.setState:

(2) requestCurrentTime, see: ReactDOM.render() for React source parsing

(3) computeExpirationForFiber, see: ExpirationTime for React Source Parsing

(4) createUpdate, see: Update and UpdateQueue for React Source Parsing

(5) Note payload, which is the object that setState passed in to update

this.setState({a:1},callback) In {a:1} That is payload
//====================
update.payload = payload;

(6) enqueueUpdate, see: Update and UpdateQueue for React Source Parsing

(7) SchduleWork, which is longer, will be placed in the next section.

2. enqueueForceUpdate()
Effect:
Forces the component to re-render, also creates an update to the fiber object of the React node, and queues the update object

Source code:

  enqueueForceUpdate(inst, callback) {
    const fiber = getInstance(inst);
    const currentTime = requestCurrentTime();
    const suspenseConfig = requestCurrentSuspenseConfig();
    const expirationTime = computeExpirationForFiber(
      currentTime,
      fiber,
      suspenseConfig,
    );

    const update = createUpdate(expirationTime, suspenseConfig);
    //Unlike setState
    //Default is 0 update, need to change to 2 mandatory update
    update.tag = ForceUpdate;

    if (callback !== undefined && callback !== null) {
      if (__DEV__) {
        warnOnInvalidCallback(callback, 'forceUpdate');
      }
      update.callback = callback;
    }

    if (revertPassiveEffectsChange) {
      flushPassiveEffects();
    }
    enqueueUpdate(fiber, update);
    scheduleWork(fiber, expirationTime);
  },

Resolution:
Similar to the enqueueSetState() method, the only difference is that there are more manual changes to the value of the attribute tag:

//Unlike setState
//Default is 0 update, need to change to 2 mandatory update
update.tag = ForceUpdate;

You can see that in the createUpdate() method, the initialized tag value is UpdateState:

//Create update object
export function createUpdate(
  expirationTime: ExpirationTime,
  suspenseConfig: null | SuspenseConfig,
): Update<*> {
  return {
    // export const UpdateState = 0;
    // export const ReplaceState = 1;
    // export const ForceUpdate = 2;
    // export const CaptureUpdate = 3;

    //Focus on CaptureUpdate, which has an ErrorBoundaries feature after React16
    //That is, errors were reported during the rendering process. You can update the page by choosing a new rendering state (which indicates an incorrect state)
    //Default is 0 updates
    tag: UpdateState, //0Update 1 Replace 2 Force Update 3 Capturable Updates
  };
}

So change to ForceUpdate so React can prioritize Update

3. Overall
The process by which React is updated after setState or forUpdate is executed is:
(1) Get the fiber object on this
(2) Calculate current time
(3) Calculate expirationTime of the fiber object from (1) fiber and (2) currentTime
(4) Create update objects from (3) expirationTime
(5) Assign the object to be updated in setState to (4) update.payload
(6) Assign the callback to be executed in setState to (4) update.callback
(7) update enrollment updateQueue
(8) Scheduling tasks

(finished)

Tags: Javascript React Attribute

Posted on Sun, 08 Sep 2019 19:33:36 -0700 by BDKR