react advanced Lecture 4 - life cycle

Class component lifecycle

When fiber tag = 1 is found, class components are encountered.

/* workloop React Main functions and methods of processing class components */
function updateClassComponent(){
    let shouldUpdate
    const instance = workInProgress.stateNode // stateNode is the pointer of fiber to the instance of class component.
     // Instance is a component instance. If the component instance does not exist, it proves that this kind of component has not been mounted, then the initialization process will be followed
     if (instance === null) { 
        // 1. workInProgress tree, the fiber tree currently being reconciled. 2. Component is the class component in the project. 3. nextProps is the new props in an update as a component.
        constructClassInstance(workInProgress, Component, nextProps); // The component instance will be new in this method
        // renderExpirationTime is the expiration time for the next rendering.
        mountClassInstance(workInProgress,Component, nextProps,renderExpirationTime );  //Initialize the process of mounting components.  
        // The shouldUpdate ID is used to prove whether the component needs to be updated.
        shouldUpdate = true;
     }else{  
        // Update component process
        shouldUpdate = updateClassInstance(current, workInProgress, Component, nextProps, renderExpirationTime)
     }
     if(shouldUpdate){
         nextChildren = instance.render(); /* Execute the render function to get the child nodes */
         // Current tree. In the initialization update, current = null. After the first fiber reconciliation, the workInProgress tree will be assigned to the current tree.
        reconcileChildren(current,workInProgress,nextChildren,renderExpirationTime) /* Continue to reconcile child nodes */
     }
}

Most of the life cycle of React is executed in two methods, mountClassInstance and updateClassInstance.

Initialization phase

function mountClassInstance(workInProgress,ctor,newProps,renderExpirationTime) {
    const instance = workInProgress.stateNode;
    const getDerivedStateFromProps = ctor.getDerivedStateFromProps; /* ctor It is the class component we write to obtain the static method of the class component */
    if (typeof getDerivedStateFromProps === 'function') {
        const partialState = getDerivedStateFromProps(nextProps, prevState); // Get the state to be merged 
        const memoizedState = partialState === null || partialState === undefined ? prevState : Object.assign({}, prevState, partialState); // Merge state
        workInProgress.memoizedState = memoizedState;
        instance.state = workInProgress.memoizedState; // This is the state we obtained from this.state in the component
    }
    // When getDerivedStateFromProps and getSnapshotBeforeUpdate do not exist 
    if(typeof ctor.getDerivedStateFromProps !== 'function' &&   typeof instance.getSnapshotBeforeUpdate !== 'function' && typeof instance.componentWillMount === 'function' ) {
        instance.componentWillMount(); 
    }
}

Update phase

/**
* current: current Tree. In the initialization update, current = null. After the first fiber reconciliation, the workInProgress tree will be assigned to the current tree.
* workInProgress: fiber tree currently being reconciled
* ctor: Is the class component we write
**/
function updateClassInstance(current,workInProgress,ctor,newProps,renderExpirationTime) {
    const instance = workInProgress.stateNode;
    const hasNewLifecycles =  typeof ctor.getDerivedStateFromProps === 'function'
    if(!hasNewLifecycles && typeof instance.componentWillReceiveProps === 'function') {
        if (oldProps !== newProps || oldContext !== nextContext) {     // Shallow comparison props are not equal
            instance.componentWillReceiveProps(newProps, nextContext);  // Execution lifecycle  
         } 
    }
    let newState = (instance.state = oldState);
    if (typeof getDerivedStateFromProps === 'function')  {
        ctor.getDerivedStateFromProps(nextProps,prevState)  /* Execute the life cycle getDerivedStateFromProps. The logic is similar to mounted. Merge state  */
        newState = workInProgress.memoizedState;
    }
    let shouldUpdate = true    
    if(typeof instance.shouldComponentUpdate === 'function' ){
        shouldUpdate = instance.shouldComponentUpdate(newProps,newState,nextContext);
    }
    if(shouldUpdate){
        if (typeof instance.componentWillUpdate === 'function') {
            instance.componentWillUpdate(); /* Execute lifecycle componentWillUpdate  */
        }
    }
    return shouldUpdate
}

  • Initialization phase: constructor - > getderivedstatefromprops / componentwillmount - > render - > componentdidmount
  • Update phase: componentwillreceiveprops (props change) / getderivedstatefromprop - > shouldcomponentupdate - > render - > getsnapshotbeforeupdate - > componentdidupdate
  • Uninstall phase: componentWillUnMount
  1. constructor:
  • It is called when the class component creates an instance and executed once during initialization, so you can do some initialization in the constructor.
  1. getDerivedStateFromProps:
  • Replace componentWillMount and componentWillReceiveProps
  • When the component is initialized or updated, map props to state.
  • Return an object to update the state. If null is returned, nothing will be updated.
getDerivedStateFromProps(nextProps,prevState)

The getDerivedStateFromProps method is executed as a static property method of the class, and this cannot be accessed internally.

  1. The later version of componentWillUpdate is obsolete and should not be used
  2. getSnapshotBeforeUpdate
  • It is used together with componentDidUpdate to form a snapShot and pass it to componentDidUpdate. Save the information before an update.
getSnapshotBeforeUpdate(prevProps,preState) { return xxx}

Function component lifecycle

  1. useEffect
useEffect(()=>{
    const subscription = props.source.subscribe();
      return () => {
        // Clear subscription
        subscription.unsubscribe();
      };
},dep)

useEffect(()=>{
    return destory
},dep)
  • useEffect is the first parameter callback, and the returned destory is called before the next callback execution to remove the side effects from the previous callback. The previous effect is cleared before the next effect is executed.
  • The second parameter, as a dependency, is an array that can have multiple dependencies. When the dependency changes, execute the destruction returned by the last callback, and execute the new effect. The first parameter callback.
  • For the execution of useEffect, asynchronous call is adopted. The callback of each effect will be put into the task queue and executed until the main thread task is completed. Therefore, the effect callback function does not block the browser drawing view.
  1. useLayoutEffect
  • useLayoutEffect adopts synchronous execution, which is executed before DOM drawing.
  • Code execution in uselayouteeffect callback will block browser drawing.

Q: What is the difference between useeffect and componentDidMount / componentDidUpdate execution timing?

A: useEffect is executed asynchronously and does not block browser drawing. componentDidMount / componentDidUpdate are executed synchronously

How to use useEffect instead of componentDidMount?

A:

React.useEffect(()=>{
    /* Request data, event listening, manipulation dom */
},[])  /* Remember dep = [] */

ß

Tags: React

Posted on Sun, 28 Nov 2021 19:46:24 -0500 by cmanhatton