updateClassComponent
- instance 不存在,current存在就断开alternate指针,将组件类实例化并挂载
- instance存在,current存在进行实例更新处理
function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps,
  renderExpirationTime: ExpirationTime,
) {
  let hasContext;
  if (isLegacyContextProvider(Component)) {
    hasContext = true;
    pushLegacyContextProvider(workInProgress);
  } else {
    hasContext = false;
  }
  prepareToReadContext(workInProgress, renderExpirationTime);
  const instance = workInProgress.stateNode;
  let shouldUpdate;
  //实例是否存在
  if (instance === null) {
      //current存在,断开alertnate指针
    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.
    // 调用组件的构造器,进行实例化
    constructClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
    //挂载实例
    mountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
    shouldUpdate = true;
  } else if (current === null) {
    // In a resume, we'll already have an instance we can reuse.
    shouldUpdate = resumeMountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  } else {
      //存在current
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  }
  const nextUnitOfWork = finishClassComponent(
    current,
    workInProgress,
    Component,
    shouldUpdate,
    hasContext,
    renderExpirationTime,
  );
  return nextUnitOfWork;
}
constructClassInstance
- 对context进行处理,读取context
- new ctor(props, context)构造实例
- 给ClassComponent 的实例挂载一个updater对象
- 给instace属性_reactInternalFiber上挂载fiber对象
function constructClassInstance(
  workInProgress: Fiber,
  ctor: any,
  props: any,
  renderExpirationTime: ExpirationTime,
): any {
  let isLegacyContextConsumer = false;
  let unmaskedContext = emptyContextObject;
  let context = null;
  const contextType = ctor.contextType;
  if (typeof contextType === 'object' && contextType !== null) {
    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;
  }
  const instance = new ctor(props, context);
  const state = (workInProgress.memoizedState =
    instance.state !== null && instance.state !== undefined
      ? instance.state
      : null);
  adoptClassInstance(workInProgress, instance);
  // 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;
}
function adoptClassInstance(workInProgress: Fiber, instance: any): void {
  instance.updater = classComponentUpdater;
  workInProgress.stateNode = instance;
  // The instance needs access to the fiber so that it can schedule updates
  setInstance(instance, workInProgress);
}
//setInstance就是set 方法。
export function set(key, value) {
  key._reactInternalFiber = value;
}
mountClassInstance
- 处理updateQueue,有则计算更新
- 有getDerivedStateFromProps方法就调用之
- 判断是否有componentDidMount 有就修改effectTag
function mountClassInstance(
  workInProgress: Fiber,
  ctor: any,
  newProps: any,
  renderExpirationTime: ExpirationTime,
): void {
  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);
  }
  let updateQueue = workInProgress.updateQueue;
  if (updateQueue !== null) {
    processUpdateQueue(
      workInProgress,
      updateQueue,
      newProps,
      instance,
      renderExpirationTime,
    );
    instance.state = workInProgress.memoizedState;
  }
  const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
  if (typeof getDerivedStateFromProps === 'function') {
    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.
  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.
    updateQueue = workInProgress.updateQueue;
    if (updateQueue !== null) {
      processUpdateQueue(
        workInProgress,
        updateQueue,
        newProps,
        instance,
        renderExpirationTime,
      );
      instance.state = workInProgress.memoizedState;
    }
  }
  if (typeof instance.componentDidMount === 'function') {
    workInProgress.effectTag |= Update;
  }
}
export function applyDerivedStateFromProps(
  workInProgress: Fiber,
  ctor: any,
  getDerivedStateFromProps: (props: any, state: any) => any,
  nextProps: any,
) {
  const prevState = workInProgress.memoizedState;
  const partialState = getDerivedStateFromProps(nextProps, prevState);
  // Merge the partial state and the previous state.
  const memoizedState =
    partialState === null || partialState === undefined
      ? prevState
      : Object.assign({}, prevState, partialState);
  workInProgress.memoizedState = memoizedState;
  // Once the update queue is empty, persist the derived state onto the
  // base state.
  const updateQueue = workInProgress.updateQueue;
  if (updateQueue !== null && workInProgress.expirationTime === NoWork) {
    updateQueue.baseState = memoizedState;
  }
}
finishClassComponent
- 加上ref的effectTag
- 判断shouldUpdate,为false,就bailout
- 调用instance.render方法返回nextChildren
- 调用reconcileChildren
- 将instance的state赋值workInProgress的memoizedState
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);
  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;
  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 {
      nextChildren = instance.render();
  }
  // React DevTools reads this flag.
  workInProgress.effectTag |= 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 {
    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;
}
updateClassInstance
- 读取context
- 调用getDerivedStateFromProps
- 调用更新阶段生命周期
- 处理更新,检查是否应该更新 - function updateClassInstance( current: Fiber, workInProgress: Fiber, ctor: any, newProps: any, renderExpirationTime: ExpirationTime, ): boolean { const instance = workInProgress.stateNode; const oldProps = workInProgress.memoizedProps; instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); const oldContext = instance.context; const contextType = ctor.contextType; let nextContext; if (typeof contextType === 'object' && contextType !== null) { nextContext = readContext(contextType); } else { const nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); } const getDerivedStateFromProps = ctor.getDerivedStateFromProps; const hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; // Note: During these life-cycles, instance.props/instance.state are what // ever the previously attempted to render - not the "current". However, // during componentDidUpdate we pass the "current" props. // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for components using the new APIs. if ( !hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function') ) { if (oldProps !== newProps || oldContext !== nextContext) { callComponentWillReceiveProps( workInProgress, instance, newProps, nextContext, ); } } resetHasForceUpdateBeforeProcessing(); const oldState = workInProgress.memoizedState; let newState = (instance.state = oldState); let updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { processUpdateQueue( workInProgress, updateQueue, newProps, instance, renderExpirationTime, ); newState = workInProgress.memoizedState; } if ( oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing() ) { // If an update was already in progress, we should schedule an Update // effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidUpdate === 'function') { if ( oldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.effectTag |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if ( oldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.effectTag |= Snapshot; } } return false; } if (typeof getDerivedStateFromProps === 'function') { applyDerivedStateFromProps( workInProgress, ctor, getDerivedStateFromProps, newProps, ); newState = workInProgress.memoizedState; } const shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate( workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext, ); if (shouldUpdate) { // In order to support react-lifecycles-compat polyfilled components, // Unsafe lifecycles should not be invoked for components using the new APIs. if ( !hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function') ) { startPhaseTimer(workInProgress, 'componentWillUpdate'); if (typeof instance.componentWillUpdate === 'function') { instance.componentWillUpdate(newProps, newState, nextContext); } if (typeof instance.UNSAFE_componentWillUpdate === 'function') { instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); } stopPhaseTimer(); } if (typeof instance.componentDidUpdate === 'function') { workInProgress.effectTag |= Update; } if (typeof instance.getSnapshotBeforeUpdate === 'function') { workInProgress.effectTag |= Snapshot; } } else { // If an update was already in progress, we should schedule an Update // effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidUpdate === 'function') { if ( oldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.effectTag |= Update; } } if (typeof instance.getSnapshotBeforeUpdate === 'function') { if ( oldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.effectTag |= Snapshot; } } // If shouldComponentUpdate returned false, we should still update the // memoized props/state to indicate that this work can be reused. workInProgress.memoizedProps = newProps; workInProgress.memoizedState = newState; } // Update the existing instance's state, props, and context pointers even // if shouldComponentUpdate returns false. instance.props = newProps; instance.state = newState; instance.context = nextContext; return shouldUpdate; }
总结一下
- 分为两个主要阶段,挂载阶段和更新阶段,两个阶段处理不太一样
- 挂载阶段会实例化组件,挂载updater等,关联instace和fiber
- 更新阶段主要是调用更新阶段的个别生命周期,判断是否是要更新
- 两个阶段都会调用finishClassComponent返回nextUnitOfWork