React 类组件源码浅析

Posted 小张的成长历程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 类组件源码浅析相关的知识,希望对你有一定的参考价值。

虽然现在都是使用函数组件,但是类组件还是有函数组件无法替代的地方,比如一些独有的生命周期、很方便的存一些变量而不需要一大堆useRef、实例的方法调用更方便。

以下源码浅析React版本为17.0.1。

类组件的Fiber节点的创建

类组件的Fiber节点由父级节点进入reconcileChildren方法后通过createFiberFromTypeAndProps方法创建,在这个方法中会通过prototype.isReactComponent判断该节点是否为ClassComponent

export function createFiberFromTypeAndProps(
  type: any, // React$ElementType
  key: null | string,
  pendingProps: any,
  owner: null | Fiber,
  mode: TypeOfMode,
  lanes: Lanes,
): Fiber 
{
  // 省略无关代码...
  let fiberTag = IndeterminateComponent;
  if (typeof type === 'function') {
    // 通过prototype.isReactComponent判断是不是类组件
    if (shouldConstruct(type)) {
      // 标记为类组件
      fiberTag = ClassComponent;
    }
  } 
  // 省略无关代码...
  return fiber;
}

// 通过prototype.isReactComponent判断是不是类组件
function shouldConstruct(Component: Function{
  const prototype = Component.prototype;
  return !!(prototype && prototype.isReactComponent);
}

由于类组件需要继承Component,所有存在prototype.isReactComponent,该节点被标记为类组件,后续会进入类组件的判断。

类组件实例的创建和更新

上一步标记了该Fiber节点为ClassComponent,该节点进入beginWork阶段时会通过判断进入updateClassComponent方法。

// ...省略无关代码
case ClassComponent: {
  // 类组件type是类的本身,不是类的实例
  const Component = workInProgress.type;
  const unresolvedProps = workInProgress.pendingProps;
  // 合并defaultProps
  const resolvedProps =
    workInProgress.elementType === Component
      ? unresolvedProps
      : resolveDefaultProps(Component, unresolvedProps);
  return updateClassComponent(
    current,
    workInProgress,
    Component,
    resolvedProps,
    renderLanes,
  );
}
// ...省略无关代码

无论类组件是首次挂载还是更新,都会进入updateClassComponent

function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps: any,
  renderLanes: Lanes,
{
  // 省略无关代码...
    
  // 类实例
  const instance = workInProgress.stateNode;
  let shouldUpdate;
  // mount
  if (instance === null) {
    // 省略无关代码...
    // 创建并初始化类实例
    constructClassInstance(workInProgress, Component, nextProps);
    mountClassInstance(workInProgress, Component, nextProps, renderLanes);
    shouldUpdate = true;
  } else if (current === null) {
    // 中断后继续渲染...
  } else {
    // update
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      Component,
      nextProps,
      renderLanes,
    );
  }
  // 返回子Fiber节点
  const nextUnitOfWork = finishClassComponent(
    current,
    workInProgress,
    Component,
    shouldUpdate,
    hasContext,
    renderLanes,
  );

  return nextUnitOfWork;
}

updateClassComponent中会针对Mount和Update分开判断。

Mount时

Mount时会创建实例,赋值updater(也就是setStateforceUpdate等),初始化updateQueue。主要调用了constructClassInstance方法和mountClassInstance`方法。

constructClassInstance

constructClassInstance方法主要创建类实例并绑定到Fiber节点,赋值updater

function constructClassInstance(
  workInProgress: Fiber,
  ctor: any,
  props: any,
): any 
{
  let isLegacyContextConsumer = false;
  let unmaskedContext = emptyContextObject;
  let context = emptyContextObject;
  // 省略context相关代码...

  // 创建实例
  const instance = new ctor(props, context);
  // 将state赋值到fiber节点的memoizedState
  const state = (workInProgress.memoizedState =
    instance.state !== null && instance.state !== undefined
      ? instance.state
      : null);
  // 赋值updater
  adoptClassInstance(workInProgress, instance);
    
  // 省略无关代码...
    
  return instance;
}

function adoptClassInstance(workInProgress: Fiber, instance: any): void {
  // 赋值updater
  instance.updater = classComponentUpdater;
  workInProgress.stateNode = instance;
  // 通过instance._reactInternals属性可以访问fiber节点
  setInstance(instance, workInProgress);
}

mountClassInstance

mountClassInstance方法会对类实例的propsstate赋值,并初始化updateQueue,同时执行getDerivedStateFromProps生命周期获取新的state,同时根据判断执行componentWillMount生命周期。

后续state的值会通过执行updateQueue的中的update来更新。

function mountClassInstance(
  workInProgress: Fiber,
  ctor: any,
  newProps: any,
  renderLanes: Lanes,
): void 
{
  // 类实例
  const instance = workInProgress.stateNode;
  // 赋值props,state
  instance.props = newProps;
  instance.state = workInProgress.memoizedState;
  instance.refs = emptyRefsObject;
  // 初始化UpdateQueue
  initializeUpdateQueue(workInProgress);

  const contextType = ctor.contextType;
  if (typeof contextType === 'object' && contextType !== null) {
    // 把context挂在实例的context上
    instance.context = readContext(contextType);
  }

  // 执行updateQueue计算新的state
  processUpdateQueue(workInProgress, newProps, instance, renderLanes);
  instance.state = workInProgress.memoizedState;

  const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
  // 执行getDerivedStateFromProps赋值给state
  if (typeof getDerivedStateFromProps === 'function') {
    applyDerivedStateFromProps(
      workInProgress,
      ctor,
      getDerivedStateFromProps,
      newProps,
    );
    instance.state = workInProgress.memoizedState;
  }

 // 调用componentWillMount
  if (
    typeof ctor.getDerivedStateFromProps !== 'function' &&
    typeof instance.getSnapshotBeforeUpdate !== 'function' &&
    (typeof instance.UNSAFE_componentWillMount === 'function' ||
      typeof instance.componentWillMount === 'function')
  ) {
    // 调用UNSAFE_componentWillMount
    callComponentWillMount(workInProgress, instance);
    // 执行updateQueue处理UNSAFE_componentWillMount里发起的update
    processUpdateQueue(workInProgress, newProps, instance, renderLanes);
    // 赋值新的state
    instance.state = workInProgress.memoizedState;
  }

  // 有componentDidMount的情况下flags增加Update
  if (typeof instance.componentDidMount === 'function') {
    workInProgress.flags |= Update;
  }
}

Update时

Update时调用updateClassInstance来处理更新。

updateClassInstance

function updateClassInstance(
  current: Fiber,
  workInProgress: Fiber,
  ctor: any,
  newProps: any,
  renderLanes: Lanes,
): boolean 
{
  // 类实例
  const instance = workInProgress.stateNode;
  // clone当前updateQueue到workInProgress
  cloneUpdateQueue(current, workInProgress);

  // 当fiber走完beginWork阶段,memoizedProps会被赋值为pendingProps
  const unresolvedOldProps = workInProgress.memoizedProps;
  const oldProps =
    workInProgress.type === workInProgress.elementType
      ? unresolvedOldProps
      : resolveDefaultProps(workInProgress.type, unresolvedOldProps);
  instance.props = oldProps;
  const unresolvedNewProps = workInProgress.pendingProps;

  // context
  const oldContext = instance.context;
  const contextType = ctor.contextType;
  let nextContext = emptyContextObject;
  if (typeof contextType === 'object' && contextType !== null) {
    nextContext = readContext(contextType);
  } // ...

  const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
  // 是否使用了新的生命周期
  const hasNewLifecycles =
    typeof getDerivedStateFromProps === 'function' ||
    typeof instance.getSnapshotBeforeUpdate === 'function';

  // 调用UNSAFE_componentWillReceiveProps
  if (
    !hasNewLifecycles &&
    (typeof instance.UNSAFE_componentWillReceiveProps === 'function' ||
      typeof instance.componentWillReceiveProps === 'function')
  ) {
    if (
      unresolvedOldProps !== unresolvedNewProps ||
      oldContext !== nextContext
    ) {
      callComponentWillReceiveProps(
        workInProgress,
        instance,
        newProps,
        nextContext,
      );
    }
  }

  // 执行updateQueue之前重置forceUpdate标识
  resetHasForceUpdateBeforeProcessing();

  const oldState = workInProgress.memoizedState;
  let newState = (instance.state = oldState);
  // 执行updateQueue获取新的state
  processUpdateQueue(workInProgress, newProps, instance, renderLanes);
  newState = workInProgress.memoizedState;

  // 没看懂这段
  if (
    unresolvedOldProps === unresolvedNewProps &&
    oldState === newState &&
    !hasContextChanged() &&
    !checkHasForceUpdateAfterProcessing()
  ) {
    if (typeof instance.componentDidUpdate === 'function') {
      if (
        unresolvedOldProps !== current.memoizedProps ||
        oldState !== current.memoizedState
      ) {
        workInProgress.flags |= Update;
      }
    }
    if (typeof instance.getSnapshotBeforeUpdate === 'function') {
      if (
        unresolvedOldProps !== current.memoizedProps ||
        oldState !== current.memoizedState
      ) {
        workInProgress.flags |= Snapshot;
      }
    }
    return false;
  }

  // 执行getDerivedStateFromProps
  if (typeof getDerivedStateFromProps === 'function') {
    applyDerivedStateFromProps(
      workInProgress,
      ctor,
      getDerivedStateFromProps,
      newProps,
    );
    newState = workInProgress.memoizedState;
  }

  // 根据forceUpdate标识和shouldComponentUpdate执行结果判断是否需要更新
  const shouldUpdate =
    checkHasForceUpdateAfterProcessing() ||
    checkShouldComponentUpdate(
      workInProgress,
      ctor,
      oldProps,
      newProps,
      oldState,
      newState,
      nextContext,
    );

  // 需要更新
  if (shouldUpdate) {
    // 调用UNSAFE_componentWillUpdate生命周期
    if (
      !hasNewLifecycles &&
      (typeof instance.UNSAFE_componentWillUpdate === 'function' ||
        typeof instance.componentWillUpdate === 'function')
    ) {
      if (typeof instance.componentWillUpdate === 'function') {
        instance.componentWillUpdate(newProps, newState, nextContext);
      }
      if (typeof instance.UNSAFE_componentWillUpdate === 'function') {
        instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext);
      }
    }
    if (typeof instance.componentDidUpdate === 'function') {
      workInProgress.flags |= Update;
    }
    if (typeof instance.getSnapshotBeforeUpdate === 'function') {
      workInProgress.flags |= Snapshot;
    }
  } else {
    // 没看懂这段
    if (typeof instance.componentDidUpdate === 'function') {
      if (
        unresolvedOldProps !== current.memoizedProps ||
        oldState !== current.memoizedState
      ) {
        workInProgress.flags |= Update;
      }
    }
    if (typeof instance.getSnapshotBeforeUpdate === 'function') {
      if (
        unresolvedOldProps !== current.memoizedProps ||
        oldState !== current.memoizedState
      ) {
        workInProgress.flags |= Snapshot;
      }
    }

    workInProgress.memoizedProps = newProps;
    workInProgress.memoizedState = newState;
  }

  // 更新实例的props,state,context
  instance.props = newProps;
  instance.state = newState;
  instance.context = nextContext;

  return shouldUpdate;
}

finishClassComponent

Mount和Update后都需要执行finishClassComponent方法,该方法会返回经过reconcileChildren处理后的child节点。

function finishClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  shouldUpdate: boolean,
  hasContext: boolean,
  renderLanes: Lanes,
{
  // 标记需要赋值ref
  markRef(current, workInProgress);

  const didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags;

  // 不需要更新
  if (!shouldUpdate && !didCaptureError) {
    return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
  }

  const instance = workInProgress.stateNode;

  let nextChildren;
  // 出错了并且getDerivedStateFromError没有声明
  if (
    didCaptureError &&
    typeof Component.getDerivedStateFromError !== 'function'
  ) {
    // 不渲染children,后续交给componentDidCatch处理
    nextChildren = null;
  } else {
    // 执行render获取children
    nextChildren = instance.render();
  }

  if (current !== null && didCaptureError) {
    forceUnmountCurrentAndReconcile(
      current,
      workInProgress,
      nextChildren,
      renderLanes,
    );
  } else {
    // 处理children
    reconcileChildren(current, workInProgress, nextChildren, renderLanes);
  }

  workInProgress.memoizedState = instance.state;

  return workInProgress.child;
}

类组件的更新调度

类的更新存在于Fiber节点上的updateQueue,上面存储了Update的信息,类组件可以通过setState创建Update并添加到updateQueue发起更新调度,在Update时执行updateClassInstance方法时会调用processUpdateQueue方法计算新的state

UpdateQueue和Update的结构

在类组件Mount时执行mountClassInstance方法时,内部会调用initializeUpdateQueue方法初始化updateQueue

export function initializeUpdateQueue<State>(fiber: Fiber): void {
  const queue: UpdateQueue<State> = {
    baseState: fiber.memoizedState, // update基于baseState计算新的state
    firstBaseUpdatenull// 优先级相关,被跳过的update
    lastBaseUpdatenull,  // 优先级相关,被跳过的update
    shared: {
      pendingnull// 当前更新的update链表
    },
    effectsnull// update的callback,对应setState第二个参数
  };
  fiber.updateQueue = queue; // 初始化
}

通过执行setState会调用createUpdate方法创建update,并添加到updateQueue中,Update是一个环形链表,next字段指向下一个Update

export function createUpdate(eventTime: number, lane: Lane): Update<*> {
  const update: Update<*> = {
    eventTime,
    lane, // 优先级相关

    tag: UpdateState, // 根据tag判断更新state值
    payloadnull// 对应setState的第一个参数
    callbacknull// 对应setState的第二个参数

    nextnull// 由于是链表结构,指向下一个update
  };
  return update;
}

processUpdateQueue

在类组件Update时会调用processUpdateQueue方法中会执行updateQueue来获得新的state

// 执行updateQueue
export function processUpdateQueue<State>(
  workInProgress: Fiber,
  props: any,
  instance: any,
  renderLanes: Lanes,
): void 
{
  // ClassComponent中总是不为null
  const queue: UpdateQueue<State> = (workInProgress.updateQueue: any);

  // 全局标识判断是不是通过forceUpdate发起的更新
  hasForceUpdate = false;

  // 由于优先级在上次更新被跳过的update链表
  let firstBaseUpdate = queue.firstBaseUpdate;
  let lastBaseUpdate = queue.lastBaseUpdate;

  // 如果本次更新有pending updates,就拼接到baseUpdate
  let pendingQueue = queue.shared.pending;
  if (pendingQueue !== null) {
    queue.shared.pending = null;
    // 断开最后一个和第一个的连接,这样pendingQueue就不是环状了
    const lastPendingUpdate = pendingQueue;
    const firstPendingUpdate = lastPendingUpdate.next;
    lastPendingUpdate.next = null;
    // 把pending updates连接到base queue
    if (lastBaseUpdate === null) {
      firstBaseUpdate = firstPendingUpdate;
    } else {
      lastBaseUpdate.next = firstPendingUpdate;
    }
    lastBaseUpdate = lastPendingUpdate;

    // 保证current和workInProgress一致
    const current = workInProgress.alternate;
    if (current !== null) {
      // 省略代码...
    }
  }

  if (firstBaseUpdate !== null) {
    let newState = queue.baseState;
    let newLanes = NoLanes;

    let newBaseState = null;
    let newFirstBaseUpdate = null;
    let newLastBaseUpdate = null;

    let update = firstBaseUpdate;
    do {
      const updateLane = update.lane;
      const updateEventTime = update.eventTime;
      // 优先级不够的任务
      if (!isSubsetOfLanes(renderLanes, updateLane)) {
        // clone跳过的Update
        const clone: Update<State> = {
          eventTime: updateEventTime,
          lane: updateLane,

          tag: update.tag,
          payload: update.payload,
          callback: update.callback,

          nextnull,
        };
       
        // 连接到firstBaseUpdate或lastBaseUpdate
        if (newLastBaseUpdate === null) {
          newFirstBaseUpdate = newLastBaseUpdate = clone;
          // 有跳过的Update下次以此时的state值计算
          newBaseState = newState;
        } else {
          newLastBaseUpdate = newLastBaseUpdate.next = clone;
        }
        newLanes = mergeLanes(newLanes, updateLane);
      } else {
        // 优先级够不会被跳过的Update

        // 如果之前有被跳过的update,为了保证下次更新的连续性,也需要添加进laseBaseUpdate
        if (newLastBaseUpdate !== null) {
          const clone: Update<State> = {
            eventTime: updateEventTime,
            // NoLane在下次执行时不会被上面优先级不够跳过
            lane: NoLane,

            tag: update.tag,
            payload: update.payload,
            callback: update.callback,

            nextnull,
          };
          newLastBaseUpdate = newLastBaseUpdate.next = clone;
        }

        // 根据update计算新的state
        newState = getStateFromUpdate(
          workInProgress,
          queue,
          update,
          newState,
          props,
          instance,
        );
        const callback = update.callback;
        // 回调函数push进effects数组
        if (callback !== null) {
          workInProgress.flags |= Callback;
          const effects = queue.effects;
          if (effects === null) {
            queue.effects = [update];
          } else {
            effects.push(update);
          }
        }
      }
      // 下一个update
      update = update.next;
      if (update === null) {
        pendingQueue = queue.shared.pending;
        if (pendingQueue === null) {
          break;
        } else {
          // setState函数里又调用了setState会进入这个判断
          const lastPendingUpdate = pendingQueue;
          const firstPendingUpdate = ((lastPendingUpdate.next: any): Update<State>);
          lastPendingUpdate.next = null;
          update = firstPendingUpdate;
          queue.lastBaseUpdate = lastPendingUpdate;
          queue.shared.pending = null;
        }
      }
    } while (true);

    if (newLastBaseUpdate === null) {
      newBaseState = newState;
    }

    queue.baseState = ((newBaseState: any): State);
    queue.firstBaseUpdate = newFirstBaseUpdate;
    queue.lastBaseUpdate = newLastBaseUpdate;

    markSkippedUpdateLanes(newLanes);
    workInProgress.lanes = newLanes;
    workInProgress.memoizedState = newState; // 反应到页面的state值
  }

}

processUpdateQueue方法里会执行updateQueue计算新的state值,主要是其中包含了优先级以及跳过的Update的判断有一些障目。主要逻辑还是循环Update链表来获得新的state

state值会通过getStateFromUpdate方法来获得。

getStateFromUpdate

getStateFromUpdate函数内会根据Update类型来处理state,这里主要关注由setState发起的UpdateState类型。

function getStateFromUpdate<State>(
  workInProgress: Fiber,
  queue: UpdateQueue<State>,
  update: Update<State>,
  prevState: State,
  nextProps: any,
  instance: any,
): any 
{
  switch (update.tag) {
    // 省略代码...
    // tag为UpdateState
    case UpdateState: {
      const payload = update.payload;
      let partialState;
      if (typeof payload === 'function') {
        // 当第一个参数是函数时
        partialState = payload.call(instance, prevState, nextProps);
      } else {
        // 第一个参数是对象
        partialState = payload;
      }
      if (partialState === null || partialState === undefined) {
        return prevState;
      }
      // 合并state
      return Object.assign({}, prevState, partialState);
    },
    // tag为ForceUpdate
    case ForceUpdate: {
      hasForceUpdate = true;
      return prevState;
    }
  }
  return prevState;
}

setState和forceUpdate

setState方法和forceUpdate方法是继承Component后原型链上的方法,本质是调用的在Mount时赋值当this.updater

Component.prototype.setState = function(partialState, callback{
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
Component.prototype.forceUpdate = function(callback{
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};

this.updater是在Mount时在constructClassInstance方法里调用adoptClassInstance方法时赋值的。

// adoptClassInstance...
instance.updater = classComponentUpdater;
// 通过instance._reactInternals属性可以访问fiber节点
setInstance(instance, workInProgress);

classComponentUpdater

updater本质调用的就是classComponentUpdater的方法。

const classComponentUpdater = {
  enqueueSetState(inst, payload, callback) {
    // 从实例的_reactInternals属性取出fiber节点
    const fiber = getInstance(inst);
    const eventTime = requestEventTime();
    const lane = requestUpdateLane(fiber);

    // 创建update
    const update = createUpdate(eventTime, lane);
    update.payload = payload;
    if (callback !== undefined && callback !== null) {
      update.callback = callback;
    }

    // Update入队
    enqueueUpdate(fiber, update);
    // 发起更新调度
    scheduleUpdateOnFiber(fiber, lane, eventTime);
  },
  enqueueForceUpdate(inst, callback) {
    const fiber = getInstance(inst);
    const eventTime = requestEventTime();
    const lane = requestUpdateLane(fiber);

    const update = createUpdate(eventTime, lane);
    update.tag = ForceUpdate;

    if (callback !== undefined && callback !== null) {
      update.callback = callback;
    }

    enqueueUpdate(fiber, update);
    scheduleUpdateOnFiber(fiber, lane, eventTime);
  },
};

setStateforceUpdate主要区别是Updatetag类型不同,在执行updateQueue通过Update获取state时,getStateFromUpdate方法返回不同的结果。

它们的回调函数会在后续的commit阶段执行。

类组件生命周期的执行

以下生命周期不包含未来不推荐使用的UNSAFE生命周期,省略了部分无关代码。

render阶段

在未来开启concurrent模式后,目前UNSAFE的生命周期可能会因为渲染中断或优先级的高低执行多次,虽然目前不会有任何问题,但还是应该尽量避免使用。

constructor

constructor在执行的时候实际上会传入context作为第二个参数,这个在文档上是没有的。

function constructClassInstance(
// ...
): any 
{
  // 创建实例
  const instance = new ctor(props, context);
}

shouldComponentUpdate

shouldComponentUpdate在Update时通过updateClassInstance方法里每次都会调用。

function updateClassInstance(
// ...
): boolean 
{
  const shouldUpdate =
  checkHasForceUpdateAfterProcessing() ||
   // 调用shouldComponentUpdate
  checkShouldComponentUpdate(
    workInProgress,
    ctor,
    oldProps,
    newProps,
    oldState,
    newState,
    nextContext,
  );
}

getDerivedStateFromProps

getDerivedStateFromProps就像文档写的***会在每次渲染前触发此方法***,它在Mount时和Update时都会调用,通过执行函数获取一个新的state值,并且会合并到当前state上,同时会维护某些情况下updateQueuebaseState值。

// ...
const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') {
  applyDerivedStateFromProps(
    workInProgress,
    ctor,
    getDerivedStateFromProps,
    newProps,
  );
  // 赋值给
  instance.state = workInProgress.memoizedState;
}

componentDidMount

虽然在render阶段不会执行componentDidMount,但是它会在render阶段打上flags,后续commit阶段才会执行。

function mountClassInstance(
// ...
): void 
{
  // 有componentDidMount的情况下flags增加Update
  if (typeof instance.componentDidMount === 'function') {
    workInProgress.flags |= Update;
  }
}

componentDidMount和getSnapshotBeforeUpdate

componentDidMount相同,在render阶段需要打上flags,但是会判断propsstate有没有变化。

function updateClassInstance(
// ...
): boolean 
{
  if (typeof instance.componentDidUpdate === 'function') {
    if (
      unresolvedOldProps !== current.memoizedProps ||
      oldState !== current.memoizedState
    ) {
      workInProgress.flags |= Update;
    }
  }
  if (typeof instance.getSnapshotBeforeUpdate === 'function') {
    if (
      unresolvedOldProps !== current.memoizedProps ||
      oldState !== current.memoizedState
    ) {
      workInProgress.flags |= Snapshot;
    }
  }
}

commit阶段

commit阶段又分为3个阶段

  • BeforeMutation阶段
  • Mutation阶段
  • Layout阶段

BeforeMutation阶段

BeforeMutation阶段在操作DOM前。

getSnapshotBeforeUpdate

通过current判断是否为Update时,并执行getSnapshotBeforeUpdate方法,按照文档的描述,这个生命周期可以做滚动条的位置,因为这时候获取DOM的值还是旧的。

function commitBeforeMutationLifeCycles(
  current: Fiber | null,
  finishedWork: Fiber,
): void 
{
  switch (finishedWork.tag) {
    // ...
    case ClassComponent: {
      // 判断flags有Snapshot,在render阶段会打上flags
      if (finishedWork.flags & Snapshot) {
        // 通过current判断当前为Mount还是Update
        if (current !== null) {
          const prevProps = current.memoizedProps;
          const prevState = current.memoizedState;
          const instance = finishedWork.stateNode;
          
          const snapshot = instance.getSnapshotBeforeUpdate(
            finishedWork.elementType === finishedWork.type
              ? prevProps
              : resolveDefaultProps(finishedWork.type, prevProps),
            prevState,
          );
          // 返回值是存在一个内部变量里的
          instance.__reactInternalSnapshotBeforeUpdate = snapshot;
        }
      }
      return;
    }
    // ...
  }
}

Mutation阶段

Mution阶段正在对DOM进行操作。

componentWillUnMount

当Fiber节点flags包含Deletion时,最后会进入commitUnmount方法,由safelyCallComponentWillUnmount方法调用componentWillUnMount

function commitUnmount(
  finishedRoot: FiberRoot,
  current: Fiber,
  renderPriorityLevel: ReactPriorityLevel,
): void 
{
  switch (current.tag) {
    // ...
    case ClassComponent: {
      safelyDetachRef(current);
      const instance = current.stateNode;
      if (typeof instance.componentWillUnmount === 'function') {
        safelyCallComponentWillUnmount(current, instance);
      }
      return;
    }
    // ...
  }
}

Layout阶段

Layou阶段是操作DOM后。

componentDidMount和componentDidMount

componentDidMountcomponentDidMount在同一个函数中执行,通过current === null判断是Mount还是Update来确定执行哪一个函数。

function commitLifeCycles(
  finishedRoot: FiberRoot,
  current: Fiber | null,
  finishedWork: Fiber,
  committedLanes: Lanes,
): void 
{
  switch (finishedWork.tag) {
    case ClassComponent: {
      const instance = finishedWork.stateNode;
      if (finishedWork.flags & Update) {
        // mount时
        if (current === null) {
          // 执行componentDidMount
          instance.componentDidMount();
        } else {
          // update时,从current Fiber节点取出之前的props和state
          const prevProps =
            finishedWork.elementType === finishedWork.type
              ? current.memoizedProps
              : resolveDefaultProps(finishedWork.type, current.memoizedProps);
          const prevState = current.memoizedState;

          instance.componentDidUpdate(
            prevProps,
            prevState,
            instance.__reactInternalSnapshotBeforeUpdate,
          );
        }
      }

      // 这里会执行updateQueue上的effects,其中存的是setState和forceUpdate的callback
      const updateQueue: UpdateQueue<
        *,
      > | null = (finishedWork.updateQueue: any);
      if (updateQueue !== null) {
        commitUpdateQueue(finishedWork, updateQueue, instance);
      }
      return;
    }
  }
}

总结

以上简单从源码简单分析了类组件Fiber节点创建、类组件实例创建、更新,发起更新调度,生命周期的执行,回头再对比Hooks,我觉得某些情况类组件真的还挺方便,虽然大部分功能函数组件都能实现,但是还是的花一些时间使用Hooks来实现对应功能。


以上是关于React 类组件源码浅析的主要内容,如果未能解决你的问题,请参考以下文章

react-redux 源码浅析

React事件机制源码浅析

react-redux 源码浅析

React中Diff算法源码浅析

react源码系列 — 创建元素组件

react源码系列 — 创建元素组件