Skip to content

ClassComponent 组件

对于 Class 类型的组件, 在 beginWork 中,主要做了以下工作:

  1. 将组件的 FiberNode 节点转换成对应的 Dom 节点,并存放到 fiber.stateNode
  2. 处理 Class 组件生命周期函数
  3. 处理组件的 Context 上下文

updateClassComponent 函数

处理组件的上下文 context

  1. 处理旧版上下文逻辑 getChildContext
  2. prepareToReadContext 方法为处理上下文进行准备工作
  3. constructClassInstance 方法中,根据以下优先级去处理上下文的值
    • 是否存在 contextType 对象,存在则通过 readContext 方法读取 context 对象
    • 是否存在 contextTypes 对象,存在则通过 getMaskedContext 方法读取 context 对象
    • 以上都不存在,则返回空对象
js
function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps: any,
  renderLanes: Lanes
) {
  // 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.
  let hasContext;
  if (isLegacyContextProvider(Component)) {
    hasContext = true;
    pushLegacyContextProvider(workInProgress);
  } else {
    hasContext = false;
  }
  prepareToReadContext(workInProgress, renderLanes);

  return nextUnitOfWork;
}

function constructClassInstance(
  workInProgress: Fiber,
  ctor: any,
  props: any
): any {
  let isLegacyContextConsumer = false;
  let unmaskedContext = emptyContextObject;
  let context = emptyContextObject;
  // 获取 class 对象上的 contextType 属性
  const contextType = ctor.contextType;

  // 1. 获取初始化的时候传入的 context 值
  if (typeof contextType === "object" && contextType !== null) {
    // 读取 Class.contextType 传入的 context 对象
    context = readContext((contextType: any));
  } else if (!disableLegacyContext) {
    //
    unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
    const contextTypes = ctor.contextTypes;
    isLegacyContextConsumer =
      contextTypes !== null && contextTypes !== undefined;
    context = isLegacyContextConsumer
      ? getMaskedContext(workInProgress, unmaskedContext)
      : emptyContextObject;
  }
  // 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;
}

首次渲染

判断条件

js
instance === null;

执行逻辑

constructClassInstance(workInProgress, Component, nextProps)

  1. 处理 Class 组件的 context 值
  2. 执行 Class 组件的 constructor 方法

根据第一步处理好的 context 的值,执行 Class 组件的 constructor 方法,创建 Class 组件的实例。

js
// 执行 Class 的 constructor 方法, 并传入 props 和 context
let instance = new ctor(props, context);
  1. 处理 FiberNode.stateNodeinstace._reactInternal 的关联关系

主要是修改以下几个属性的指向

  • FiberNode.stateNode === instace , 指向 Class 组件的实例对象 instance
  • instance._reactInternals === FiberNode ,Class 组件的实例对象指向 FiberNode
js
/**
 * 修改FiberNode的几个属性
 *  - 修改 stateNode 指向 Class 组件的实例对象 instance
 *  - 修改FiberNode.stateNode._reactInternals 指向 FiberNode
 *  - 修改FiberNode.stateNode.updater 指向 classComponentUpdater
 * @param {*} workInProgress
 * @param {*} instance
 */
function adoptClassInstance(workInProgress: Fiber, instance: any): void {
  instance.updater = classComponentUpdater;
  // 将 FiberNode.stateNode 指向实例对象
  workInProgress.stateNode = instance;
  // The instance needs access to the fiber so that it can schedule updates
  // 将 Class 组件的实例对象 和 FiberNode._reactInternals 关联起来
  setInstance(instance, workInProgress);
  if (__DEV__) {
    instance._reactInternalInstance = fakeInternalInstance;
  }
}
  1. 缓存 context 对象到 instance.**reactInternalMemoizedUnmaskedChildContextinstance.__reactInternalMemoizedMaskedChildContext

mountClassInstance(workInProgress, Component, nextProps, renderLanes)

执行 Class 组件的 FiberNode 到 dom 的生命周期函数

  1. 执行 getDerivedStateFromProps 方法

从 Props 中获得 State,所以该函数的功能就是从更新后的 props 中获取 State,它让组件在 props 发生改变时更新它自身的内部 state。

  1. 执行 componentWillMount 生命周期方法
js
/**
 * 调用 Class 组件的 componentWillMount 方法  和 unsafe_componentWillMount 方法
 * 根据返回的新旧 state 是否发生了变化, 决定是否需要重新渲染组件
 *    如果发生了变化, 则执行 classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
 * @param {*} workInProgress
 * @param {*} instance
 */
function callComponentWillMount(workInProgress, instance) {
  // 缓存 componentWillMount 执行之前 state 的值
  const oldState = instance.state;

  if (typeof instance.componentWillMount === "function") {
    instance.componentWillMount();
  }
  if (typeof instance.UNSAFE_componentWillMount === "function") {
    instance.UNSAFE_componentWillMount();
  }
  // 如果 state 发生了变化, 则将 state 重新赋值给 instance.state
  if (oldState !== instance.state) {
    classComponentUpdater.enqueueReplaceState(instance, instance.state, null);
  }
}

enqueueReplaceState

在 Class 组件首次渲染的时候,