国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

React16源碼: React中的updateClassComponent的源碼實現(xiàn)

這篇具有很好參考價值的文章主要介紹了React16源碼: React中的updateClassComponent的源碼實現(xiàn)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

ClassComponent 的更新


1 ) 概述

  • 在 react 中 class component,是一個非常重要的角色
  • 它承擔了 react 中 更新整個應(yīng)用的API
    • setState
    • forceUpdate
  • 在react當中,只有更新了state之后,整個應(yīng)用才會重新進行渲染
  • 在 class component 中, 它的邏輯相對復(fù)雜

2 )源碼

在 packages/react-reconciler/src/ReactFiberBeginWork.js

// 這個方法就是更新 ClassComponent 組件的一個過程
function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps,
  renderExpirationTime: ExpirationTime,
) {
  // Push context providers early to prevent context stack mismatches.
  // During mounting we don't know the child context yet as the instance doesn't exist.
  // We will invalidate the child context in finishClassComponent() right after rendering.
  // 先跳過 context 相關(guān)的邏輯
  let hasContext;
  if (isLegacyContextProvider(Component)) {
    hasContext = true;
    pushLegacyContextProvider(workInProgress);
  } else {
    hasContext = false;
  }
  prepareToReadContext(workInProgress, renderExpirationTime);

  // instance 就是我們 class component,通過new這個class獲取的一個對象
  const instance = workInProgress.stateNode;
  // 在這里面,它聲明了一個 shouldUpdate 的一個屬性
  let shouldUpdate; 
  // 先判斷instance是否存在, 比如說我們第一次通過 ReactDOM.render 進行渲染的過程當中
  // 在從上往下第一次渲染的過程當中,第一次更新到 class component 的時候
  // 它的instance肯定是不存在的,因為它還沒有被更新過,所以它的節(jié)點肯定是沒有被創(chuàng)建的
  if (instance === null) {
    // 接下去, 判斷一下current是否等于null
    // current等于null的情況是代表在進入第一次渲染,因為current它還不存在
    // 如果current不等于null, 代表我們至少已經(jīng)經(jīng)歷過一次渲染了
    // 這時候 instance 不存在,而 current 存在,說明第一次渲染的時候沒有創(chuàng)建這個instance
    // 同樣說明這個組件是被 suspended 的,一個組件處于suspended的狀態(tài)
    // 在這里react認為它相當于是第一次被渲染, 在初次渲染的時候,只是拋出了一個promise
    // 并沒有真正的渲染出它的子節(jié)點, 拋出了一個promise之后,接下去的渲染就結(jié)束了
    if (current !== null) {
      // An class component without an instance only mounts if it suspended
      // inside a non- concurrent tree, in an inconsistent state. We want to
      // tree it like a new mount, even though an empty version of it already
      // committed. Disconnect the alternate pointers.
      current.alternate = null;
      workInProgress.alternate = null;
      // Since this is conceptually a new fiber, schedule a Placement effect
      workInProgress.effectTag |= Placement;
    }
    // In the initial pass we might need to construct the instance.
    // 對于沒有instance的一個情況,需要去創(chuàng)建 class instance
    constructClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
    // 并且要mount這個 class instance
    mountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
    // 在第一次渲染的時候,會執(zhí)行上述兩個方法,并且 shouldUpdate = true;
    shouldUpdate = true;
  } else if (current === null) {
    // In a resume, we'll already have an instance we can reuse.
    // 在 有instance 和 沒有 current 的情況下,這種是之前被中斷的
    // 在執(zhí)行 class component 的 render 方法的時候 報錯,但 instance 已被創(chuàng)建
    // 代表著可以復(fù)用 instance
    shouldUpdate = resumeMountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  } else {
    // 對于又有 current 又有 instance的情況,說明組件已經(jīng)被重新渲染了
    // 這個 updateClassInstance 方法和 上述 resumeMountClassInstance 類似
    // 最大的區(qū)別是 內(nèi)部判斷 comonentDidUpdate 
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  }
  // 這里最終調(diào)用 finishClassComponent
  return finishClassComponent(
    current,
    workInProgress,
    Component,
    shouldUpdate,
    hasContext,
    renderExpirationTime,
  );
}
  • 進入 constructClassInstance

    function constructClassInstance(
      workInProgress: Fiber,
      ctor: any,
      props: any,
      renderExpirationTime: ExpirationTime,
    ): any {
      // 先跳過 context 相關(guān)
      let isLegacyContextConsumer = false;
      let unmaskedContext = emptyContextObject;
      let context = null;
      const contextType = ctor.contextType;
      // 
      if (typeof contextType === 'object' && contextType !== null) {
        // 跳過 DEV
        if (__DEV__) {
          if (
            contextType.$$typeof !== REACT_CONTEXT_TYPE &&
            !didWarnAboutInvalidateContextType.has(ctor)
          ) {
            didWarnAboutInvalidateContextType.add(ctor);
            warningWithoutStack(
              false,
              '%s defines an invalid contextType. ' +
                'contextType should point to the Context object returned by React.createContext(). ' +
                'Did you accidentally pass the Context.Provider instead?',
              getComponentName(ctor) || 'Component',
            );
          }
        }
    
        context = readContext((contextType: any));
      } else {
        unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
        const contextTypes = ctor.contextTypes;
        isLegacyContextConsumer =
          contextTypes !== null && contextTypes !== undefined;
        context = isLegacyContextConsumer
          ? getMaskedContext(workInProgress, unmaskedContext)
          : emptyContextObject;
      }
    
      // Instantiate twice to help detect side-effects.
      if (__DEV__) {
        if (
          debugRenderPhaseSideEffects ||
          (debugRenderPhaseSideEffectsForStrictMode &&
            workInProgress.mode & StrictMode)
        ) {
          new ctor(props, context); // eslint-disable-line no-new
        }
      }
    
      // ctor 是 construct 的一個縮寫 這個 ctor 就是在 ReactElement當中
      // 存在的那個type,也就是 class component 定義的那個class
      // 傳入 props和context,對應(yīng)于 ReactBaseClasses.js 里面,Component 函數(shù) 接收的這兩個參數(shù)
      // 第三個參數(shù) updater 后面在 adoptClassInstance 里面設(shè)置
      const instance = new ctor(props, context);
      // 獲取 state
      const state = (workInProgress.memoizedState =
        instance.state !== null && instance.state !== undefined
          ? instance.state
          : null);
      adoptClassInstance(workInProgress, instance);
    
      if (__DEV__) {
        if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) {
          const componentName = getComponentName(ctor) || 'Component';
          if (!didWarnAboutUninitializedState.has(componentName)) {
            didWarnAboutUninitializedState.add(componentName);
            warningWithoutStack(
              false,
              '`%s` uses `getDerivedStateFromProps` but its initial state is ' +
                '%s. This is not recommended. Instead, define the initial state by ' +
                'assigning an object to `this.state` in the constructor of `%s`. ' +
                'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.',
              componentName,
              instance.state === null ? 'null' : 'undefined',
              componentName,
            );
          }
        }
    
        // If new component APIs are defined, "unsafe" lifecycles won't be called.
        // Warn about these lifecycles if they are present.
        // Don't warn about react-lifecycles-compat polyfilled methods though.
        if (
          typeof ctor.getDerivedStateFromProps === 'function' ||
          typeof instance.getSnapshotBeforeUpdate === 'function'
        ) {
          let foundWillMountName = null;
          let foundWillReceivePropsName = null;
          let foundWillUpdateName = null;
          if (
            typeof instance.componentWillMount === 'function' &&
            instance.componentWillMount.__suppressDeprecationWarning !== true
          ) {
            foundWillMountName = 'componentWillMount';
          } else if (typeof instance.UNSAFE_componentWillMount === 'function') {
            foundWillMountName = 'UNSAFE_componentWillMount';
          }
          if (
            typeof instance.componentWillReceiveProps === 'function' &&
            instance.componentWillReceiveProps.__suppressDeprecationWarning !== true
          ) {
            foundWillReceivePropsName = 'componentWillReceiveProps';
          } else if (
            typeof instance.UNSAFE_componentWillReceiveProps === 'function'
          ) {
            foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps';
          }
          if (
            typeof instance.componentWillUpdate === 'function' &&
            instance.componentWillUpdate.__suppressDeprecationWarning !== true
          ) {
            foundWillUpdateName = 'componentWillUpdate';
          } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') {
            foundWillUpdateName = 'UNSAFE_componentWillUpdate';
          }
          if (
            foundWillMountName !== null ||
            foundWillReceivePropsName !== null ||
            foundWillUpdateName !== null
          ) {
            const componentName = getComponentName(ctor) || 'Component';
            const newApiName =
              typeof ctor.getDerivedStateFromProps === 'function'
                ? 'getDerivedStateFromProps()'
                : 'getSnapshotBeforeUpdate()';
            if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(componentName)) {
              didWarnAboutLegacyLifecyclesAndDerivedState.add(componentName);
              warningWithoutStack(
                false,
                'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
                  '%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' +
                  'The above lifecycles should be removed. Learn more about this warning here:\n' +
                  'https://fb.me/react-async-component-lifecycle-hooks',
                componentName,
                newApiName,
                foundWillMountName !== null ? `\n  ${foundWillMountName}` : '',
                foundWillReceivePropsName !== null
                  ? `\n  ${foundWillReceivePropsName}`
                  : '',
                foundWillUpdateName !== null ? `\n  ${foundWillUpdateName}` : '',
              );
            }
          }
        }
      }
    
      // Cache unmasked context so we can avoid recreating masked context unless necessary.
      // ReactFiberContext usually updates this cache but can't for newly-created instances.
      if (isLegacyContextConsumer) {
        cacheContext(workInProgress, unmaskedContext, context);
      }
    
      return instance;
    }
    
    • 進入 adoptClassInstance
      function adoptClassInstance(workInProgress: Fiber, instance: any): void {
        instance.updater = classComponentUpdater; // 掛載 update 方法
        workInProgress.stateNode = instance; // instance 掛載到 stateNode 以供下次進來時使用,下次進來就會存在了
        // The instance needs access to the fiber so that it can schedule updates
        ReactInstanceMap.set(instance, workInProgress);
        if (__DEV__) {
          instance._reactInternalInstance = fakeInternalInstance;
        }
      }
      
    • 進入 ReactInstanceMap 這個就是對 instance 上 _reactInternalFiber 屬性的設(shè)置
      export function remove(key) {
        key._reactInternalFiber = undefined;
      }
      
      export function get(key) {
        return key._reactInternalFiber;
      }
      
      export function has(key) {
        return key._reactInternalFiber !== undefined;
      }
      
      export function set(key, value) {
        key._reactInternalFiber = value;
      }
      
      • 這也意味著,通過 this._reactInternalFiber 就可以拿到當前 fiber 對象
  • 進入 mountClassInstance

    // Invokes the mount life-cycles on a previously never rendered instance.
    function mountClassInstance(
      workInProgress: Fiber,
      ctor: any,
      newProps: any,
      renderExpirationTime: ExpirationTime,
    ): void {
      if (__DEV__) {
        checkClassInstance(workInProgress, ctor, newProps);
      }
      
      const instance = workInProgress.stateNode;
      instance.props = newProps;
      instance.state = workInProgress.memoizedState;
      instance.refs = emptyRefsObject;
    
      const contextType = ctor.contextType;
      if (typeof contextType === 'object' && contextType !== null) {
        instance.context = readContext(contextType);
      } else {
        const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
        instance.context = getMaskedContext(workInProgress, unmaskedContext);
      }
    
      if (__DEV__) {
        if (instance.state === newProps) {
          const componentName = getComponentName(ctor) || 'Component';
          if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) {
            didWarnAboutDirectlyAssigningPropsToState.add(componentName);
            warningWithoutStack(
              false,
              '%s: It is not recommended to assign props directly to state ' +
                "because updates to props won't be reflected in state. " +
                'In most cases, it is better to use props directly.',
              componentName,
            );
          }
        }
    
        if (workInProgress.mode & StrictMode) {
          ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
            workInProgress,
            instance,
          );
    
          ReactStrictModeWarnings.recordLegacyContextWarning(
            workInProgress,
            instance,
          );
        }
    
        if (warnAboutDeprecatedLifecycles) {
          ReactStrictModeWarnings.recordDeprecationWarnings(
            workInProgress,
            instance,
          );
        }
      }
    
      // 獲取 updateQueue,初次渲染這個 updateQueue 是空的
      // 對于有 setState 的情況,它的 updateQueen 里面可能有多個update
      // 這個時候, 需要調(diào)用這個 updateQueen 來去得到一個新的state
      let updateQueue = workInProgress.updateQueue;
      if (updateQueue !== null) {
        // 這里 計算出新的state 并賦值給 workInProgress.memoizedState
        processUpdateQueue(
          workInProgress,
          updateQueue,
          newProps,
          instance,
          renderExpirationTime,
        );
        // 同時更新 instance.state
        instance.state = workInProgress.memoizedState;
      }
      
      // 判斷是否有這個生命周期方法
      const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
      if (typeof getDerivedStateFromProps === 'function') {
        // 如果存在該生命周期方法,則計算新的state
        // 這個生命周期會在組件更新的過程中被調(diào)用
        applyDerivedStateFromProps(
          workInProgress,
          ctor,
          getDerivedStateFromProps,
          newProps,
        );
        instance.state = workInProgress.memoizedState;
      }
    
      // In order to support react-lifecycles-compat polyfilled components,
      // Unsafe lifecycles should not be invoked for components using the new APIs.
      // 判斷是否有 componentWillMount 生命周期方法
      // 在這個生命周期方法中,會執(zhí)行 setState 方法
      if (
        typeof ctor.getDerivedStateFromProps !== 'function' &&
        typeof instance.getSnapshotBeforeUpdate !== 'function' &&
        (typeof instance.UNSAFE_componentWillMount === 'function' ||
          typeof instance.componentWillMount === 'function')
      ) {
        // 
        callComponentWillMount(workInProgress, instance);
        // If we had additional state updates during this life-cycle, let's
        // process them now.
        // 執(zhí)行了 這個生命周期方法,就需要重新執(zhí)行 updateQueue
        // 如果在這時執(zhí)行了 setState, 立馬被反映到組件上面
        updateQueue = workInProgress.updateQueue;
        if (updateQueue !== null) {
          processUpdateQueue(
            workInProgress,
            updateQueue,
            newProps,
            instance,
            renderExpirationTime,
          );
          instance.state = workInProgress.memoizedState;
        }
      }
    
      if (typeof instance.componentDidMount === 'function') {
        workInProgress.effectTag |= Update;
      }
    }
    
    • 進入 processUpdateQueue
      export function processUpdateQueue<State>(
        workInProgress: Fiber,
        queue: UpdateQueue<State>,
        props: any,
        instance: any,
        renderExpirationTime: ExpirationTime,
      ): void {
        hasForceUpdate = false;
        // 克隆 updateQueue
        queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
      
        if (__DEV__) {
          currentlyProcessingQueue = queue;
        }
      
        // These values may change as we process the queue.
        let newBaseState = queue.baseState;
        let newFirstUpdate = null;
        let newExpirationTime = NoWork;
      
        // Iterate through the list of updates to compute the result.
        let update = queue.firstUpdate; 
        let resultState = newBaseState;
        while (update !== null) {
          const updateExpirationTime = update.expirationTime;
          if (updateExpirationTime < renderExpirationTime) {
            // This update does not have sufficient priority. Skip it.
            if (newFirstUpdate === null) {
              // This is the first skipped update. It will be the first update in
              // the new list.
              newFirstUpdate = update;
              // Since this is the first update that was skipped, the current result
              // is the new base state.
              newBaseState = resultState;
            }
            // Since this update will remain in the list, update the remaining
            // expiration time.
            if (newExpirationTime < updateExpirationTime) {
              newExpirationTime = updateExpirationTime;
            }
          } else {
            // This update does have sufficient priority. Process it and compute
            // a new result.
            resultState = getStateFromUpdate(
              workInProgress,
              queue,
              update,
              resultState,
              props,
              instance,
            );
            const callback = update.callback;
            // 判斷是否有 callback
            if (callback !== null) {
              workInProgress.effectTag |= Callback; // 加上 Callback 這塊
              // Set this to null, in case it was mutated during an aborted render.
              update.nextEffect = null; // 防止在中斷的渲染中被修改
              if (queue.lastEffect === null) {
                queue.firstEffect = queue.lastEffect = update; // 鏈表操作
              } else {
                queue.lastEffect.nextEffect = update;
                queue.lastEffect = update;
              }
            }
          }
          // Continue to the next update.
          update = update.next;
        }
      
        // Separately, iterate though the list of captured updates.
        let newFirstCapturedUpdate = null;
        update = queue.firstCapturedUpdate;
        while (update !== null) {
          const updateExpirationTime = update.expirationTime;
          if (updateExpirationTime < renderExpirationTime) {
            // This update does not have sufficient priority. Skip it.
            if (newFirstCapturedUpdate === null) {
              // This is the first skipped captured update. It will be the first
              // update in the new list.
              newFirstCapturedUpdate = update;
              // If this is the first update that was skipped, the current result is
              // the new base state.
              if (newFirstUpdate === null) {
                newBaseState = resultState;
              }
            }
            // Since this update will remain in the list, update the remaining
            // expiration time.
            if (newExpirationTime < updateExpirationTime) {
              newExpirationTime = updateExpirationTime;
            }
          } else {
            // This update does have sufficient priority. Process it and compute
            // a new result.
            resultState = getStateFromUpdate(
              workInProgress,
              queue,
              update,
              resultState,
              props,
              instance,
            );
            const callback = update.callback;
            if (callback !== null) {
              workInProgress.effectTag |= Callback;
              // Set this to null, in case it was mutated during an aborted render.
              update.nextEffect = null;
              if (queue.lastCapturedEffect === null) {
                queue.firstCapturedEffect = queue.lastCapturedEffect = update;
              } else {
                queue.lastCapturedEffect.nextEffect = update;
                queue.lastCapturedEffect = update;
              }
            }
          }
          update = update.next;
        }
      
        if (newFirstUpdate === null) {
          queue.lastUpdate = null;
        }
        if (newFirstCapturedUpdate === null) {
          queue.lastCapturedUpdate = null;
        } else {
          workInProgress.effectTag |= Callback;
        }
        if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
          // We processed every update, without skipping. That means the new base
          // state is the same as the result state.
          newBaseState = resultState;
        }
      
        queue.baseState = newBaseState;
        queue.firstUpdate = newFirstUpdate;
        queue.firstCapturedUpdate = newFirstCapturedUpdate;
      
        // Set the remaining expiration time to be whatever is remaining in the queue.
        // This should be fine because the only two other things that contribute to
        // expiration time are props and context. We're already in the middle of the
        // begin phase by the time we start processing the queue, so we've already
        // dealt with the props. Context in components that specify
        // shouldComponentUpdate is tricky; but we'll have to account for
        // that regardless.
        workInProgress.expirationTime = newExpirationTime;
        workInProgress.memoizedState = resultState;
      
        if (__DEV__) {
          currentlyProcessingQueue = null;
        }
      }
      
      • 進入 ensureWorkInProgressQueueIsAClone
      function ensureWorkInProgressQueueIsAClone<State>(
        workInProgress: Fiber,
        queue: UpdateQueue<State>,
      ): UpdateQueue<State> {
        const current = workInProgress.alternate;
        if (current !== null) {
          // If the work-in-progress queue is equal to the current queue,
          // we need to clone it first.
          if (queue === current.updateQueue) {
            // 要保證 workInProgress.updateQueue 是一個克隆的queue, 而非直接進行修改
            queue = workInProgress.updateQueue = cloneUpdateQueue(queue); // 拷貝 queue
          }
        }
        return queue;
      }
      
    • 進入 getStateFromUpdate
      function getStateFromUpdate<State>(
        workInProgress: Fiber,
        queue: UpdateQueue<State>,
        update: Update<State>,
        prevState: State,
        nextProps: any,
        instance: any,
      ): any {
        switch (update.tag) {
          case ReplaceState: {
            const payload = update.payload;
            if (typeof payload === 'function') {
              // Updater function
              if (__DEV__) {
                if (
                  debugRenderPhaseSideEffects ||
                  (debugRenderPhaseSideEffectsForStrictMode &&
                    workInProgress.mode & StrictMode)
                ) {
                  payload.call(instance, prevState, nextProps);
                }
              }
              return payload.call(instance, prevState, nextProps);
            }
            // State object
            return payload;
          }
          // 這里 a & ~b 表示: a & 除了b之外的所有屬性
          case CaptureUpdate: {
            workInProgress.effectTag =
              (workInProgress.effectTag & ~ShouldCapture) | DidCapture; // 這里最終剩下的 只有 DidCapture
          }
          // Intentional fallthrough
          case UpdateState: {
            const payload = update.payload;
            let partialState;
            if (typeof payload === 'function') {
              // Updater function
              if (__DEV__) {
                if (
                  debugRenderPhaseSideEffects ||
                  (debugRenderPhaseSideEffectsForStrictMode &&
                    workInProgress.mode & StrictMode)
                ) {
                  payload.call(instance, prevState, nextProps);
                }
              }
              // 如果是 function 則調(diào)用 payload 傳入之前的參數(shù) 計算出 state
              partialState = payload.call(instance, prevState, nextProps);
            } else {
              // Partial state object
              partialState = payload;
            }
            // 處理特殊情況
            if (partialState === null || partialState === undefined) {
              // Null and undefined are treated as no-ops.
              return prevState;
            }
            // Merge the partial state and the previous state.
            // 合并
            return Object.assign({}, prevState, partialState);
          }
          case ForceUpdate: {
            hasForceUpdate = true;
            return prevState;
          }
        }
        return prevState;
      }
      
  • 進入 finishClassComponent

    function finishClassComponent(
      current: Fiber | null,
      workInProgress: Fiber,
      Component: any,
      shouldUpdate: boolean,
      hasContext: boolean,
      renderExpirationTime: ExpirationTime,
    ) {
      // Refs should update even if shouldComponentUpdate returns false
      // 這個先跳過
      markRef(current, workInProgress);
    
      // 判斷 workInProgress.effectTag 上是否有 DidCapture
      const didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect;
      // 在沒有更新也沒有錯誤捕獲的情況下
      if (!shouldUpdate && !didCaptureError) {
        // Context providers should defer to sCU for rendering
        if (hasContext) {
          invalidateContextProvider(workInProgress, Component, false);
        }
        // 跳過更新
        return bailoutOnAlreadyFinishedWork(
          current,
          workInProgress,
          renderExpirationTime,
        );
      }
    
      const instance = workInProgress.stateNode;
    
      // Rerender
      ReactCurrentOwner.current = workInProgress;
      let nextChildren;
      // 有任何錯誤捕獲, 但沒有配置這個api的時候
      // 這個 getDerivedStateFromError 生命周期的api和 componentDidCatch 有區(qū)別, 后者在下次更新的時候處理,中間可能instance不存在(因為出錯了)
      // 就繼續(xù)可能引發(fā)在這個class component上面設(shè)置的 ref拿到一個null, 操作ref的時候就會出現(xiàn)錯誤
      // 在前者這個新的生命周期的api中, 在本次渲染中,生成 state, 渲染出屬性, 這樣對于 instance 對象依然存在 對應(yīng) ref 就可以拿到實際的對象
      if (
        didCaptureError &&
        typeof Component.getDerivedStateFromError !== 'function'
      ) {
        // If we captured an error, but getDerivedStateFrom catch is not defined,
        // unmount all the children. componentDidCatch will schedule an update to
        // re-render a fallback. This is temporary until we migrate everyone to
        // the new API.
        // TODO: Warn in a future release.
        nextChildren = null;
    
        if (enableProfilerTimer) {
          stopProfilerTimerIfRunning(workInProgress);
        }
      } else {
        if (__DEV__) {
          ReactCurrentFiber.setCurrentPhase('render');
          nextChildren = instance.render();
          if (
            debugRenderPhaseSideEffects ||
            (debugRenderPhaseSideEffectsForStrictMode &&
              workInProgress.mode & StrictMode)
          ) {
            instance.render();
          }
          ReactCurrentFiber.setCurrentPhase(null);
        } else {
          // 調(diào)用 render 方法,計算出新的 children
          nextChildren = instance.render();
        }
      }
    
      // React DevTools reads this flag.
      workInProgress.effectTag |= PerformedWork; // 增加 PerformedWork
      // 不是第一次渲染,并且有錯誤捕獲
      if (current !== null && didCaptureError) {
        // If we're recovering from an error, reconcile without reusing any of
        // the existing children. Conceptually, the normal children and the children
        // that are shown on error are two different sets, so we shouldn't reuse
        // normal children even if their identities match.
        forceUnmountCurrentAndReconcile(
          current,
          workInProgress,
          nextChildren,
          renderExpirationTime,
        );
      } else {
        // 正常情況調(diào)用 調(diào)和 children
        reconcileChildren(
          current,
          workInProgress,
          nextChildren,
          renderExpirationTime,
        );
      }
    
      // Memoize state using the values we just used to render.
      // TODO: Restructure so we never read values from the instance.
      workInProgress.memoizedState = instance.state;
    
      // The context might have changed so we need to recalculate it.
      if (hasContext) {
        invalidateContextProvider(workInProgress, Component, true);
      }
    
      return workInProgress.child; // 把 render 方法渲染出來的第一個子節(jié)點 返回給 nextUnitOfWork, 就可以在 workLoop 中繼續(xù)進行更新的流程
    }
    
  • 簡單總結(jié)文章來源地址http://www.zghlxwxcb.cn/news/detail-811799.html

    • 以上是更新 class component 的整體流程
    • 一開始要使用 constructClassInstance 創(chuàng)建 class instance
    • 內(nèi)部會根據(jù)不同情況調(diào)用不同方法
    • 并且要調(diào)用 mountClassInstance 來掛載
    • 如果是第一次渲染被中斷的情況
      • 如果存在 instance 則重復(fù)使用 instance
      • 它調(diào)用的生命周期方法仍然是 第一次渲染的生命周期方法
      • 也就是 componentDidMount
    • 如果不是第一次渲染的情況
      • 調(diào)用 updateClassInstance 方法
      • 這種會最終調(diào)用 componentDidUpdate 方法
    • 它們中間的流程類似
      • 判斷各種情況,創(chuàng)建新的 instance 或 復(fù)用之前的
      • 通過 processUpdateQueue 來獲取新的 state
      • 會把它賦值到 instance 和 fiber 上面進行記錄
      • 最終都會調(diào)用 finishClassComponent
        • 這里面做一些錯誤判斷的處理
        • 以及是否可以跳過更新的過程
        • 還有重新調(diào)和子節(jié)點 (通用流程)

到了這里,關(guān)于React16源碼: React中的updateClassComponent的源碼實現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • React16源碼: React中的beginWork的源碼實現(xiàn)

    beginWork 1 )概述 在 renderRoot 之后,要對我們的 Fiber 樹每一個節(jié)點進行對應(yīng)的更新 更新節(jié)點的一個入口方法,就是 beginWork 這個入口方法會有幫助我們?nèi)?yōu)化整棵樹的更新過程 react 它的節(jié)點其實是非常多的,如果每一次子節(jié)點的一個更新 就需要每一個節(jié)點都執(zhí)行一遍更新的話

    2024年01月20日
    瀏覽(24)
  • React16源碼: React中的updateHostRoot的源碼實現(xiàn)

    HostRoot 的更新 1 )概述 HostRoot 是一個比較特殊的節(jié)點, 因為在一個react應(yīng)用當中 它只會有一個 HostRoot , 它對應(yīng)的 Fiber 對象是我們的 RootFiber 對象 重點在于它的更新過程 2 )源碼 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js#L612 HostRoot 創(chuàng)建更新的過程就是在 ReactFiberReconcile

    2024年01月22日
    瀏覽(29)
  • React16源碼: React中的IndeterminateComponent的源碼實現(xiàn)

    IndeterminateComponent 1 )概述 這是一個比較特殊的component的類型, 就是還沒有被指定類型的component 在一個fibrer被創(chuàng)建的時候,它的tag可能會是 IndeterminateComponent 在 packages/react-reconciler/src/ReactFiber.js 中,有一個方法 createFiberFromTypeAndProps 中,一開始就聲明了 在最終調(diào)用 createFibe

    2024年01月21日
    瀏覽(20)
  • React16源碼: React中的completeUnitOfWork的源碼實現(xiàn)

    React16源碼: React中的completeUnitOfWork的源碼實現(xiàn)

    completeUnitOfWork 1 )概述 各種不同類型組件的一個更新過程對應(yīng)的是在執(zhí)行 performUnitOfWork 里面的 beginWork 階段 它是去向下遍歷一棵 fiber 樹的一側(cè)的子節(jié)點,然后遍歷到葉子節(jié)點為止,以及 return 自己 child 的這種方式 在 performUnitOfWork 里面,還有一個方法叫做 completeUnitOfWork 在

    2024年01月23日
    瀏覽(33)
  • React16源碼: React中的setState和forceUpdate源碼實現(xiàn)

    setState 和 forceUpdate 1 ) 概述 通過 class component 內(nèi)部的 setState ,以及 forceUpdate 去更新一個組件的過程 在react的應(yīng)用當中,我們只有 ReactDOM.render setState ,以及 forceUpdate 這幾種種方式去更新react的應(yīng)用是合理的,其他沒有什么特別常用的方式去更新了 而且react官方推薦的也是用

    2024年01月25日
    瀏覽(22)
  • React16源碼: React中的HostComponent & HostText的源碼實現(xiàn)

    HostComponent HostText 1 )概述 HostComponent 就是我們dom原生的這些節(jié)點, 如: div, span, p 標簽這種 使用的是小寫字母開頭的這些節(jié)點一般都認為它是一個 HostComponent HostText ,它是單純的文本節(jié)點 主要關(guān)注它們的一個更新過程 2 )源碼 定位到 packages/react-reconciler/src/ReactFiberBeginWork.js 進

    2024年01月24日
    瀏覽(19)
  • React16源碼: React中的reconcileChildIterator和reconcileChildrenArray的源碼實現(xiàn)

    reconcileChildIterator 和 reconcileChildrenArray 1 )概述 在react更新某一個節(jié)點的時候,要根據(jù)這個節(jié)點,它的類型去獲取它的children 比如說如果是 Function Component,它要調(diào)用這個 component 計算出它的return的屬性 return的屬性可能是一個數(shù)組,可能是單個的 ReactElement,可能是 number, string

    2024年01月20日
    瀏覽(46)
  • React16源碼: React中的不同的expirationTime的源碼實現(xiàn)

    不同的 expirationTime 1 )概述 在React中不僅僅有異步任務(wù) 大部分情況下都是同步的任務(wù),所以會有不同 expirationTime 的存在 2 )種類 A. Sync 模式,優(yōu)先級最高 任務(wù)創(chuàng)建完成之后,立馬更新到真正的dom里面 是一個創(chuàng)建即更新的流程 B. Async 模式, 異步模式 會有一個調(diào)度 包含一系列

    2024年02月01日
    瀏覽(19)
  • React16源碼: React中的PortalComponent創(chuàng)建, 調(diào)和, 更新的源碼實現(xiàn)

    PortalComponent 1 )概述 React Portal之所以叫Portal,因為做的就是和“傳送門”一樣的事情 render到一個組件里面去,實際改變的是網(wǎng)頁上另一處的DOM結(jié)構(gòu) 主要關(guān)注 portal的創(chuàng)建, 調(diào)和, 更新過程 2 )源碼 定位到 packages/react-dom/src/client/ReactDOM.js#L576 這里調(diào)用的是 ReactPortal.createPortal ,

    2024年01月21日
    瀏覽(25)
  • React16源碼: React中的update和updateQueue的源碼實現(xiàn)

    React中的update和updateQueue 1 )概述 在 ReactDOM.render 過程中,還需要創(chuàng)建一個 update 對象 update 用于記錄組件狀態(tài)的改變的一個對象,它存放于Fiber對象的 updateQueue 中 updateQueue ,它是一個單向鏈表的結(jié)構(gòu),一次整體的更新過程當中 可能在這個queue里會存在多 Update 在這次更新的過

    2024年02月02日
    瀏覽(14)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包