# ClassComponent

begininWork 中当 workInProgress.tag 为 ClassComponent

# 合并属性

case ClassComponent: {
    const Component = workInProgress.type;
    const unresolvedProps = workInProgress.pendingProps;
    const resolvedProps =
    workInProgress.elementType === Component
        ? unresolvedProps
        : resolveDefaultProps(Component, unresolvedProps);
    // render和render之前的生命周期函数会在这里执行
    return updateClassComponent(
    current,
    workInProgress,
    Component,
    resolvedProps,
    renderExpirationTime,
    );
}

首先就是合并 props

export function resolveDefaultProps(Component: any, baseProps: Object): Object {
  if (Component && Component.defaultProps) {
    // Resolve default props. Taken from ReactElement
    const props = Object.assign({}, baseProps);
    const defaultProps = Component.defaultProps;
    for (let propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
    return props;
  }
  return baseProps;
}

Component.defaultProps 上有 默认属性时就和原本的 workInProgress.pendingProps 进行合并 然后 调用 updateClassComponent

# updateClassComponent

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) {
    if (current !== null) {
      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);
    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 {
    // 执行render之前的生命周期,render之后的生命周期打上tag标记
    // 来避免没有必要的渲染,shouldUpdate会给到finishClassComponent,来判断
    // 是否需要执行render()生命周期
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  }
  // 执行render() 生周期,获取下一个子节点
  const nextUnitOfWork = finishClassComponent(
    current,
    workInProgress,
    Component,
    shouldUpdate,
    hasContext,
    renderExpirationTime,
  );
  return nextUnitOfWork;
}

首先会判断是否有 stateNode 示例,也就是真实 DOM,如何不存在会调用 constructClassInstance 进行 new 操作

    ...
  const instance = new ctor(props, context);
  const state = (workInProgress.memoizedState =
    instance.state !== null && instance.state !== undefined
      ? instance.state
      : null);
  adoptClassInstance(workInProgress, instance);

接下来会调用 mountClassInstance 运行 render 阶段的生命周期

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;

  initializeUpdateQueue(workInProgress);

  const contextType = ctor.contextType;
  if (typeof contextType === 'object' && contextType !== null) {
    instance.context = readContext(contextType);
  } else if (disableLegacyContext) {
    instance.context = emptyContextObject;
  } else {
    const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
    instance.context = getMaskedContext(workInProgress, unmaskedContext);
  }

  processUpdateQueue(workInProgress, 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.
    processUpdateQueue(
      workInProgress,
      newProps,
      instance,
      renderExpirationTime,
    );
    instance.state = workInProgress.memoizedState;
  }

  if (typeof instance.componentDidMount === 'function') {
    workInProgress.effectTag |= Update;
  }
}
  1. 首先会初始化创建一个 UpdateQueue
  2. 判断有没有 getDerivedStateFromProps,有就执行 applyDerivedStateFromProps
  3. 判断有没有 componentWillMount,有就执行 callComponentWillMount

# updateClassInstance

初次渲染看完了 现在来看看 updateClassInstance

在这里面会进行新老 props 的对比判断,然后会触发 callComponentWillReceivePropsapplyDerivedStateFromProps 等生命周期,关键代码:

  const shouldUpdate =
    checkHasForceUpdateAfterProcessing() ||
    checkShouldComponentUpdate(
      workInProgress,
      ctor,
      oldProps,
      newProps,
      oldState,
      newState,
      nextContext,
    );

来看看 checkShouldComponentUpdate 方法

# shouldUpdate

function checkShouldComponentUpdate(
  workInProgress,
  ctor,
  oldProps,
  newProps,
  oldState,
  newState,
  nextContext,
) {
  const instance = workInProgress.stateNode;
  if (typeof instance.shouldComponentUpdate === 'function') {
    startPhaseTimer(workInProgress, 'shouldComponentUpdate');
    const shouldUpdate = instance.**shouldComponentUpdate**(
      newProps,
      newState,
      nextContext,
    );
    stopPhaseTimer();
    return shouldUpdate;
  }

  if (ctor.prototype && ctor.prototype.isPureReactComponent) {
    return (
      !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
    );
  }

  return true;
}

可以看到它会读取 我们平常写的 shouldComponentUpdate 的返回结果,如果是 PureReactComponent 的话它会自动帮我们进行浅对比

然后在 updateClassInstance 里面可以看到对 shouldUpdate 做了不同的处理

if (shouldUpdate) {
  ...
  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{
  ...
}

# finishClassComponent

上面流程走走完后会,会执行最后的方法 finishClassComponent,它的最主要作用就是 执行 render 方法获取下一个子节点,看到这里有没有很熟悉呢,这也是为什么 class 组件必须要有 rendr 方法了

... 
  // fiber.stateNode指向这个新的实例
  const instance = workInProgress.stateNode;
  ReactCurrentOwner.current = workInProgress;
  let nextChildren;
  ...
  nextChildren = instance.render();

    workInProgress.effectTag |= PerformedWork;
  if (current !== null && didCaptureError) {
    forceUnmountCurrentAndReconcile(
      current,
      workInProgress,
      nextChildren,
      renderExpirationTime,
    );
  } else {
    reconcileChildren(
      current,
      workInProgress,
      nextChildren,
      renderExpirationTime,
    );
  }
  workInProgress.memoizedState = instance.state;
  return workInProgress.child;

可以看到首先获取 fiber 的实例 stateNode ,执行 rendr 获取下一个子节点, 然后执行前面说的 reconcileChildren 继续创建 fiber 节点,然后会把实例的state 同步到 memoizedState 上 最后返回 workInProgress.child,又会回到和 我们 /react/beginWork.html#updatehostroot 流程一样

更新时间: 11/13/2020, 8:29:46 PM