react源码 - React.memo

692 阅读1分钟

React.memo

原理总结

  • 本质就是一个 REACT_MEMO_TYPE 类型的 react element,在调和阶段使用 updateMemoComponent或者 updateSimpleMemoComponent 进行处理
  1. updateMemoComponent和updateSimpleMemoComponent内部就是, 根据 compare 或者 shallowEqual 对比 props, 来确定memo包裹的组件是否命中 bailoutOnAlreadyFinishedWork.

初次渲染

updateMemoComponent
  • 在beginWork中, 通过 updateMemoComponentREACT_MEMO_TYPE类型的元素 进行处理
  1. 如果 compare === null 并且 isSimpleFunctionComponent===true(即sampleMemoComponent) , 则修改 fiber.tag===SimpleMemoComponent,在更新阶段使用 updateSimpleMemoComponent进行调和处理.
   if (
      isSimpleFunctionComponent(type) &&
      Component.compare === null
    ) {
      let resolvedType = type;
      // memo: 如果 compare === null 并且 isSimpleFunctionComponent返回true
      // 则标记 fiber.tag 为 SimpleMemoComponent
      workInProgress.tag = SimpleMemoComponent;
      workInProgress.type = resolvedType;
      return updateSimpleMemoComponent(
        current,
        workInProgress,
        resolvedType,
        nextProps,
        updateLanes,
        renderLanes,
      );
    }
  1. 如果不满足上面的条件, 则使用createFiberFromTypeAndProps创建子fiber,继续向下调和子树 ,在更新阶段使用 updateMemoComponent处理.

更新阶段

updateSimpleMemoComponent: SimpleMemoComponent
  • 使用 shallowEqual 对 props 进行浅比较
  1. 如果 props 相同并且 memo对应的fiber.lanes 不存在本次更新的lane, 命中 bailoutOnAlreadyFinishedWork 跳过子树的调和.
  2. 如果 不相同updateFunctionComponent 开始调和子树
function updateSimpleMemoComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps: any,
  updateLanes: Lanes,
  renderLanes: Lanes,
): null | Fiber {

  if (current !== null) {
    const prevProps = current.memoizedProps;
    if (
      shallowEqual(prevProps, nextProps) &&
      current.ref === workInProgress.ref &&
      // Prevent bailout if the implementation changed due to hot reload.
      (__DEV__ ? workInProgress.type === current.type : true)
    ) {
      didReceiveUpdate = false;
      if (!includesSomeLane(renderLanes, updateLanes)) {
        workInProgress.lanes = current.lanes;
        return bailoutOnAlreadyFinishedWork(
          current,
          workInProgress,
          renderLanes,
        );
      } else if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
        // This is a special case that only exists for legacy mode.
        // See https://github.com/facebook/react/pull/19216.
        didReceiveUpdate = true;
      }
    }
  }
  return updateFunctionComponent(
    current,
    workInProgress,
    Component,
    nextProps,
    renderLanes,
  );
}

updateMemoComponent
  • 如果 memo对应的fiber.lanes 不存在本次更新的lane, 根据 compare的返回结果, 判断是否命中 bailoutOnAlreadyFinishedWork,命中则跳过子树调和
  function updateMemoComponent(){  
  const currentChild = ((current.child: any): Fiber); // This is always exactly one child
  if (!includesSomeLane(updateLanes, renderLanes)) {
    // This will be the props with resolved defaultProps,
    // unlike current.memoizedProps which will be the unresolved ones.
    const prevProps = currentChild.memoizedProps;
    // Default to shallow comparison
    let compare = Component.compare;
    compare = compare !== null ? compare : shallowEqual;
    if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
      return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
    }
  }
  // React DevTools reads this flag.
  workInProgress.flags |= PerformedWork;
  // 继续调和子树
  const newChild = createWorkInProgress(currentChild, nextProps);
  newChild.ref = workInProgress.ref;
  newChild.return = workInProgress;
  workInProgress.child = newChild;
  return newChild;
  }