React.memo
原理总结
- 本质就是一个
REACT_MEMO_TYPE 类型的 react element,在调和阶段使用 updateMemoComponent或者 updateSimpleMemoComponent 进行处理
- updateMemoComponent和updateSimpleMemoComponent内部就是, 根据
compare 或者 shallowEqual 对比 props, 来确定memo包裹的组件是否命中 bailoutOnAlreadyFinishedWork.
初次渲染
updateMemoComponent
- 在beginWork中, 通过
updateMemoComponent 对 REACT_MEMO_TYPE类型的元素 进行处理
- 如果
compare === null 并且 isSimpleFunctionComponent===true(即sampleMemoComponent) , 则修改 fiber.tag===SimpleMemoComponent,在更新阶段使用 updateSimpleMemoComponent进行调和处理.
if (
isSimpleFunctionComponent(type) &&
Component.compare === null
) {
let resolvedType = type;
workInProgress.tag = SimpleMemoComponent;
workInProgress.type = resolvedType;
return updateSimpleMemoComponent(
current,
workInProgress,
resolvedType,
nextProps,
updateLanes,
renderLanes,
);
}
- 如果不满足上面的条件, 则使用
createFiberFromTypeAndProps创建子fiber,继续向下调和子树 ,在更新阶段使用 updateMemoComponent处理.
更新阶段
updateSimpleMemoComponent: SimpleMemoComponent
- 使用
shallowEqual 对 props 进行浅比较
- 如果
props 相同并且 memo对应的fiber.lanes 不存在本次更新的lane, 命中 bailoutOnAlreadyFinishedWork 跳过子树的调和.
- 如果
不相同 则 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 &&
(__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) {
didReceiveUpdate = true;
}
}
}
return updateFunctionComponent(
current,
workInProgress,
Component,
nextProps,
renderLanes,
);
}
updateMemoComponent
- 如果
memo对应的fiber.lanes 不存在本次更新的lane, 根据 compare的返回结果, 判断是否命中 bailoutOnAlreadyFinishedWork,命中则跳过子树调和
function updateMemoComponent(){
const currentChild = ((current.child: any): Fiber);
if (!includesSomeLane(updateLanes, renderLanes)) {
const prevProps = currentChild.memoizedProps;
let compare = Component.compare;
compare = compare !== null ? compare : shallowEqual;
if (compare(prevProps, nextProps) && current.ref === workInProgress.ref) {
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
}
workInProgress.flags |= PerformedWork;
const newChild = createWorkInProgress(currentChild, nextProps);
newChild.ref = workInProgress.ref;
newChild.return = workInProgress;
workInProgress.child = newChild;
return newChild;
}