当产生更新时,workInProgressTree
的 Fiber
节点有两种方式生成:
re-render
currentTree
的 Fiber
节点本文进行了以下探究:
更新时,能否复用 currentTree
的 Fiber
节点这种情况。
当调度更新时,会进入到 render
阶段,也就是产生 Fiber
的阶段,此时会调用到 beginWork
方法,该方法中对类组件和函数组件的处理如下:
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
){
switch (workInProgress.tag) {
case FunctionComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
return updateFunctionComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
case ClassComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes,
);
}
}
}
复制代码
先看 ClassComponent
的产生 Fiber
的处理再看 FunctionComponent
吧。
function updateClassComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
) {
shouldUpdate = updateClassInstance(
current,
workInProgress,
Component,
nextProps,
renderLanes,
);
const nextUnitOfWork = finishClassComponent(
current,
workInProgress,
Component,
shouldUpdate,
hasContext,
renderLanes,
);
return nextUnitOfWork;
}
复制代码
finishClassComponent
方法执行后会返回 Fiber
节点,而是否可复用 current
的 Fiber
,取决于 updateClassInstance
方法的执行结果。
来看下 updateClassInstance
:
function updateClassInstance(
current: Fiber,
workInProgress: Fiber,
ctor: any,
newProps: any,
renderLanes: Lanes,
) {
const shouldUpdate =
checkHasForceUpdateAfterProcessing() ||
checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState,
nextContext,
);
return shouldUpdate;
}
复制代码
根据 updateClassInstance
方法里,判断是否需要更新的的 2 个条件:
forceUpdate
shouldComponentUpdate
(checkShouldComponentUpdate
)可知,ClassComponent
的 Fiber
是否可复用,取决于 2 个条件:本次更新是否是调用 forceUpdate
产生的更新和 shouldComponentUpdate
方法中根据 props
判断当次是否需要更新。
function checkShouldComponentUpdate(
workInProgress,
ctor,
oldProps,
newProps,
oldState,
newState,
nextContext,
) {
const instance = workInProgress.stateNode;
if (typeof instance.shouldComponentUpdate === 'function') {
const shouldUpdate = instance.shouldComponentUpdate(
newProps,
newState,
nextContext,
);
return shouldUpdate;
}
if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
return true;
}
复制代码
根据 checkShouldComponentUpdate
的返回可知,当没有设置 shouldComponentUpdate
方法时,其效果等同于设置了 shouldComponentUpdate
但恒返回 true
,也就是 ClassComponent
会受各种因素而无故 re-render
。
下面来看 Functioncomponent
的产生 Fiber
节点的处理吧。
function updateFunctionComponent(
current,
workInProgress,
Component,
nextProps: any,
renderLanes,
) {
if (current !== null && !didReceiveUpdate) {
bailoutHooks(current, workInProgress, renderLanes);
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
}
复制代码
FunctionComponent
是否可复用 Fiber
,取决于 didReceiveUpdate
这个变量,这个变量在 beginWork
方法中被赋值:
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
){
if (
oldProps !== newProps ||
hasLegacyContextChanged() ||
(__DEV__ ? workInProgress.type !== current.type : false)
) {
didReceiveUpdate = true;
} else if (!includesSomeLane(renderLanes, updateLanes)) {
// 当优先度不足够时进入此判断
didReceiveUpdate = false;
switch(workInProgress.tag) {
// ...
}
// 有可能会执行到这,如果上面的 switch 没有 return 语句的话
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
} else {
if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
didReceiveUpdate = true;
} else {
didReceiveUpdate = false;
}
}
}
复制代码
由以上可知,当 FunctionComponent
的 props
,context
(当处于 dev
时,需要判断元素类型 type
)未变化,且本次更新的优先级足够时,didReceiveUpdate
变量会设置为 false
,在接下来的 updateFunctionComponent
方法的执行后会返回可复用的 Fiber
节点。
更新时,workInProgressTree
能否复用 currentTree
的 Fiber
节点取决于:
ClassComponent
forceUpdate
来更新的shouldComponentUpdate
中对更新的属性进行判断来决定本次更新是不需更新的FunctionComponent
dev
时,元素类型 type
不变props
不变context
没有更新[ beginWork / updateFunctionComponent / updateClassComponent / finishClassComponent] github.com/facebook/re…
[updateClassInstance / checkShouldComponentUpdate ] github.com/facebook/re…
[checkHasForceUpdateAfterProcessing] github.com/facebook/re…
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。