简介
- react版本v17.3
- 只写了函数,类,原生组件。
SuspenseComponentOffscreenComponent...等组件没写。
- 代码全部简化
- 只留核心逻辑。
- **DIFF **
reconcileChildren不讲。知道会产生新fiber即可。
工作流程
简单说,就是深度优先遍历(dfs)jsx树,生成fiber树。 react将 递归 流程转为while循环。
递归转while循环
workLoopSync、workLoopConcurrent
- while循环
workInProgress执行performUnitOfWork- 每次更新
workInProgress为 新fiber
- 每次更新
- performUnitOfWork
- beginWork
- completeUnitOfWork
- completeWork
// 同步模式
function workLoopSync() {
while (workInProgress !== null) {
performUnitOfWork(workInProgress);
}
}
// ConcurrentMode
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}
递 performUnitOfWork
- 开始工作 => 创建工作单元
fiber。- 主要工作:
childrenJSX=>childrenFiber。- 为什么每次工作都是处理
children?diff需要对新旧children进行比对。- 构建
fiber的siblingreturn等信息。 dfs递归“递”下去。每次更新workInProgress = childFber。
- 为什么每次工作都是处理
- 主要工作:
- 最终生成一棵
newFiberTree。
// dfs
function performUnitOfWork(unitOfWork: Fiber): void {
const current = unitOfWork.alternate;
// 递
let next = beginWork(current, unitOfWork, subtreeRenderLanes);
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// 归
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
}
归 completeUnitOfWork
- 完成工作 =>
fiber树构建宿主树,并渲染。- 主要工作:
fiber=>instance。 创建宿主实体- “归”是如何构建
宿主树?- 每次将
childrenFiber的instance添加到workInProgress的instance中。
- 每次将
dfs递归“归”上去,怎么实现?fiber完成 completeWork 后。- 新生成
workInProgress - 移动到
sibling return
- 新生成
- “归”是如何构建
- 主要工作:
- 最终渲染出
dom树
function completeUnitOfWork(unitOfWork: Fiber): void {
let completedWork = unitOfWork;
do {
const current = completedWork.alternate;
const returnFiber = completedWork.return;
let next = completeWork(current, completedWork, subtreeRenderLanes);
if (next !== null) {
workInProgress = next;
return;
}
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
// If there is more work to do in this returnFiber, do that next.
workInProgress = siblingFiber;
return;
}
// Otherwise, return to the parent
completedWork = returnFiber;
// Update the next thing we're working on in case something throws.
workInProgress = completedWork;
} while (completedWork !== null);
// We've reached the root.
if (workInProgressRootExitStatus === RootIncomplete) {
workInProgressRootExitStatus = RootCompleted;
}
}
公共变量
- didReceiveUpdate
- 功能:false则 表明次fiber不需要update,true表明需要update。
- 会修改此值的函数
- beginWork
- updateSimpleMemoComponent
- markWorkInProgressReceivedUpdate()
- 效果:didReceiveUpdate = true
- 调用此函数者
- renderWithHooks
- renderWithReducer
- updateReducer
- prepareToReadContext
- bailoutOnAlreadyFinishedWork
- workInProgress
- 正在工作的fiber。
beginWork
通过 workInProgress.children (JSX) 创建 childrenFiber , 返回 childFiber ,第一个子fiber。
- 为什么每次工作都是处理
children?diff需要对新旧children进行比对。- 构建
fiber的siblingreturn等信息。 dfs递归“递”下去。每次更新workInProgress = childFber。
- 逻辑:
- 判断
workInProgress是否需要update。- 判断是否存在
oldFiber,- 存在 -- 判断新旧
props是否不同,fiber 堆栈上下文是否 改变- 是 props不同
- 需要更新。didReceiveUpdate = false;
- 否 props相同
- 若 没有 current有被中断的更新。
- 不需要更新。didReceiveUpdate = false;
- return 克隆fiber,(其实就是切换alternate,继承oldFiber属性)
- 判断 是否 有
forceUpdate强制更新flags- 有
- 需要更新。didReceiveUpdate = false;
- 无
- 不需要更新。didReceiveUpdate = false;
- 有
- 若 没有 current有被中断的更新。
- 是 props不同
- 不存在 -- 说明是mount
- 不需要更新。didReceiveUpdate = false;
- 存在 -- 判断新旧
- 判断是否存在
workInProgress任务lane 重置为 无任务- 根据
workInProgress工作类型tag进入不同工作函数
- 判断
function beginWork(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
): Fiber | null {
if (current !== null) {
// update,检测是否需要更新
const oldProps = current.memoizedProps;
const newProps = workInProgress.pendingProps;
if (
oldProps !== newProps || // props不同 则更新
// Force a re-render if the implementation changed due to hot reload:
(__DEV__ ? workInProgress.type !== current.type : false)
) {
didReceiveUpdate = true;
} else {
// 通过检测lane context 是否需要更新
const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(
current,
renderLanes,
);
if (
// 无强制更新
!hasScheduledUpdateOrContext && (workInProgress.flags & DidCapture) === NoFlags
) {
didReceiveUpdate = false;
// 直接克隆旧fiber
return attemptEarlyBailoutIfNoScheduledUpdate(
current,
workInProgress,
renderLanes,
);
}
// Suspense是否有强制更新
if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {
didReceiveUpdate = true;
} else {
didReceiveUpdate = false;
}
}
} else {
// mount阶段非更新
didReceiveUpdate = false;
}
// 开始工作了,lane重置
workInProgress.lanes = NoLanes;
switch (workInProgress.tag) {
// 函数组件mount时 tag为此。执行后 修改tag。 例如不继承Component的组件。
case IndeterminateComponent: {
return mountIndeterminateComponent(
current,
workInProgress,
workInProgress.type,
renderLanes,
);
}
// 函数组件
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,
);
}
// 原生组件 div等
case HostComponent:
return updateHostComponent(current, workInProgress, renderLanes);
case HostText:
return updateHostText(current, workInProgress);
}
不同工作函数 tag -> 工作函数
reconcileChildren 是 diff 下面会讲。
HostComponent -> updateHostComponent
简介
- 处理原生组件,浏览器中为
DOM。
功能
- 生成
childrenFiber - 性能优化:子代是单文本节点,则子代不生成fiber。
逻辑
- 子代是否为单文本节点
- 是 单文本
- 子代不生成
fiber。nextChildren = null
- 子代不生成
- 不是 单文本
- 若
oldFiber是单文本- 标记内容清空
ContentReset
- 标记内容清空
- 若
- 是 单文本
markRef标记是否需要refreconcileChildrendiff- return
workInProgress.child
function updateHostComponent(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
const type = workInProgress.type;
const nextProps = workInProgress.pendingProps;
const prevProps = current !== null ? current.memoizedProps : null;
let nextChildren = nextProps.children;
// 优化:子代是否为单文本节点 eg <div>children只有一个文本节点</div>
const isDirectTextChild = shouldSetTextContent(type, nextProps);
if (isDirectTextChild) {
// 文本节点不生成fiber,commit中直接渲染文本
nextChildren = null;
} else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {
workInProgress.flags |= ContentReset;
}
markRef(current, workInProgress);
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
HostText -> updateHostText
什么都不做,直接return null。
IndeterminateComponent -> mountIndeterminateComponent
简介
function组件mount时,走此函数。历史遗留问题产物。
功能
- 生成
childrenFiber - 兼容性:处理旧react支持的工厂(
factory)函数即Function返回有class组件方法的对象。
逻辑
- 当函数组件执行 renderWithHooks 获取到
value - 判断
value是否为模拟factory class的对象。- 是
factory classtag修正为ClassComponent- 创建
class组件 - return finishClassComponent
- 否 是
函数组件tag修正为FunctionComponent- reconcileChildren
- return
workInProgress.child
- 是
function mountIndeterminateComponent(
_current,
workInProgress,
Component,
renderLanes,
) {
const props = workInProgress.pendingProps;
let context;
// 清空之前的context
prepareToReadContext(workInProgress, renderLanes);
// 运行组件函数
value = renderWithHooks(
null,
workInProgress,
Component,
props,
context,
renderLanes,
);
// 判断函数是否返回一个 有render方法的类似clas组件的对象
if (
!disableModulePatternComponents &&
typeof value === 'object' &&
value !== null &&
typeof value.render === 'function' &&
value.$$typeof === undefined
) {
// 按照ClassComponent 处理此fiber
workInProgress.tag = ClassComponent;
workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
let hasContext = false;
if (isLegacyContextProvider(Component)) {
hasContext = true;
pushLegacyContextProvider(workInProgress);
} else {
hasContext = false;
}
workInProgress.memoizedState =
value.state !== null && value.state !== undefined ? value.state : null;
initializeUpdateQueue(workInProgress);
adoptClassInstance(workInProgress, value);
mountClassInstance(workInProgress, Component, props, renderLanes);
return finishClassComponent(
null,
workInProgress,
Component,
true,
hasContext,
renderLanes,
);
} else {
// 按照FunctionComponent处理
workInProgress.tag = FunctionComponent;
// diff
reconcileChildren(null, workInProgress, value, renderLanes);
return workInProgress.child;
}
}
FunctionComponent -> updateFunctionComponent
简介
function组件update时,走此函数。- 构建hooks
功能
- 生成
childrenFiber
逻辑
- prepareToReadContext
- renderWithHooks 获取到
nextChildren - 若
current存在且didReceiveUpdate为flase则不需要更新。- bailoutHooks
- return bailoutOnAlreadyFinishedWork
- 需要更新
- reconcileChildren
- return
workInProgress.child
function updateFunctionComponent(
current,
workInProgress,
Component,
nextProps: any,
renderLanes,
) {
let context;
if (!disableLegacyContext) {
const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);
context = getMaskedContext(workInProgress, unmaskedContext);
}
let nextChildren;
// 清空之前的context
prepareToReadContext(workInProgress, renderLanes);
// 运行组件函数
nextChildren = renderWithHooks(
current,
workInProgress,
Component,
nextProps,
context,
renderLanes,
);
// 是否需要更新
if (current !== null && !didReceiveUpdate) {
bailoutHooks(current, workInProgress, renderLanes);
// 克隆旧fiber
return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);
}
// diff
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
ClassComponent -> updateClassComponent
简介
class组件走此函数。
功能
- 处理生命周期。
- 生成
childrenFiber
逻辑
- prepareToReadContext-- 清空context
- 若是
mount。 fiber.stateNode === null; class组件的stateNode值为class 实例。- constructClassInstance
- 读
context。 readContext - 执行构造函数
constructor。 - 赋值
state。fiber.memoizedState = instance.state
- 读
- mountClassInstance
fiber初始化updateQueue。 initializeUpdateQueuecontext赋值到instance.context- **生命周期 **
- applyDerivedStateFromProps(
getDerivedStateFromProps)- 更新
instance.state、fiber.memoizedState 和 ``updateQueue.baseState
- 更新
- 若只有
componentWillMount,无新Lifecycles,getDerivedStateFromProps或getSnapshotBeforeUpdate- 执行callComponentWillMount
componentWillMount- classComponentUpdater.enqueueReplaceState
- processUpdateQueue
- 更新
instance.state
- 执行callComponentWillMount
- applyDerivedStateFromProps(
- shouldUpdate = true;
- constructClassInstance
- 若是
update- shouldUpdate = updateClassInstance
- 若无新
Lifecycles则执行componentWillReceiveProps-- callComponentWillReceiveProps- 执行后,若
newState !== oldState- classComponentUpdater.enqueueReplaceState
- enqueueUpdate
- classComponentUpdater.enqueueReplaceState
- 执行后,若
- 批更新,计算
newState。 --processUpdateQueue()- 赋值
fiber.memoizedState - 能处理优先级
- 赋值
- **生命周期 **
getDerivedStateFromProps() - 若需要更新
- **生命周期 **
componentWillUpdate()
- **生命周期 **
- 若需要更新且存在
componentDidUpdate()getSnapshotBeforeUpdate()- 则
fibet.flags写入Update/Snapshot
- 则
- 更新
fibet.memoizedPropsfiber.memoizedState - class实例更新,
- 更新
instace的propsstatecontext
- 更新
- return shouldUpdate;
- 若无新
- shouldUpdate = updateClassInstance
- finishClassComponent
- 不需要更新
- bailoutOnAlreadyFinishedWork
- 需要更新
- reconcileChildren
- 不需要更新
- return
workInProgress.child
function updateClassComponent(
current: Fiber | null,
workInProgress: Fiber,
Component: any,
nextProps: any,
renderLanes: Lanes,
) {
//清空context
prepareToReadContext(workInProgress, renderLanes);
const instance = workInProgress.stateNode;
let shouldUpdate;
if (instance === null) {
if (current !== null) {
current.alternate = null;
workInProgress.alternate = null;
workInProgress.flags |= Placement;
}
// 读取context,执行构造函数,赋值state
constructClassInstance(workInProgress, Component, nextProps);
// fiber初始化updateQueue,context赋值到实例
mountClassInstance(workInProgress, Component, nextProps, renderLanes);
shouldUpdate = true;
} else if (current === null) {
// 复用实例
shouldUpdate = resumeMountClassInstance(
workInProgress,
Component,
nextProps,
renderLanes,
);
} else {
// 计算state,执行 及将更新 相关的生命周期
shouldUpdate = updateClassInstance(
current,
workInProgress,
Component,
nextProps,
renderLanes,
);
}
// 就行检测 需要更新则diff 不需要更新则克隆
const nextUnitOfWork = finishClassComponent(
current,
workInProgress,
Component,
shouldUpdate,
hasContext,
renderLanes,
);
return nextUnitOfWork;
}
Fragment -> updateFragment
简介
- 处理Fragment组件
- pendingProps是childrenJSX
功能
- 生成
childrenFiber
逻辑
- reconcileChildren
- return
workInProgress.child
function updateFragment(
current: Fiber | null,
workInProgress: Fiber,
renderLanes: Lanes,
) {
const nextChildren = workInProgress.pendingProps;
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
updateHostRoot
创建react组件root 功能:
- Reconciler协调
rootFiber,通过reconcileChildren和jsx,构建children fiber返回child fiber。
逻辑:
fiberRoot的state.element值为jsx,即ReactDOM.render中的第一个值。- 通过
state.element来reconcileChildren
CompleteWork
为 workInProgress 创建/更新 stateNode 。
将 childrenFiber 的 stateNode 全部添加到 workInProgress.stateNode 中。 subtreeFlags, childLanes 会向上冒泡。
mount 时:创建dom,设置属性
update 时:diff props, 创建updateQueue。 commit中处理.
- 为什么要将所有
child的stateNode添加到workInProgress.stateNode中?- 最终root会形成dom树,方便直接插入dom树。
- 逻辑:
- 根据
workInProgress工作类型tag进入不同switch块- 主要工作是处理
HostComponent。 - Class Function组件只向上冒泡
flags,lane。bubbleProperties。
- 主要工作是处理
- 根据
不同工作函数 tag -> switch块
HostComponent
功能
- 创建/更新 dom
逻辑
- 若为更新。
current !== null && workInProgress.stateNode != nullupdateHostComponent- 新旧props不同则更新。
workInProgress.updateQueue = prepareUpdate- 进行
dom属性的diff updatePayload([key,value]数组,i为修改属性, i+1为修改的值) / null
- 进行
- 新旧ref不同,
markRef
- 若为创建
createInstance- 创建dom
appendAllChildren- 将
childrenFiber的stateNode全部添加到workInProgress.stateNode中
- 将
finalizeInitialChildren- 设置属性。
- 处理子节点为单文本节点的情况。 setTextContent(domElement, nextProp)
- 设置属性。
markRef
bubbleProperties- return null
const rootContainerInstance = getRootHostContainer();
const type = workInProgress.type;
if (current !== null && workInProgress.stateNode != null) {
updateHostComponent(
current,
workInProgress,
type,
newProps,
rootContainerInstance,
);
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
} else {
// mount dom插入
const currentHostContext = getHostContext();
const instance = createInstance(
type,
newProps,
rootContainerInstance,
currentHostContext,
workInProgress,
);
appendAllChildren(instance, workInProgress, false, false);
workInProgress.stateNode = instance;
if (
finalizeInitialChildren(instance,type,newProps,rootContainerInstance,currentHostContext,)
) {
markUpdate(workInProgress);
}
if (workInProgress.ref !== null) {
markRef(workInProgress);
}
}
bubbleProperties(workInProgress);
return null;
HostText -> updateHostText
功能
- 创建/更新 text节点
逻辑
- 若为更新。
current !== null && workInProgress.stateNode != nullupdateHostText- 标记Update.
- 若为创建
createTextInstance- 创建text节点
bubbleProperties- return null
const newText = newProps;
if (current && workInProgress.stateNode != null) {
const oldText = current.memoizedProps;
// flags写入 update
updateHostText(current, workInProgress, oldText, newText);
} else {
const rootContainerInstance = getRootHostContainer();
const currentHostContext = getHostContext();
// 创建文本节点
workInProgress.stateNode = createTextInstance(
newText,
rootContainerInstance,
currentHostContext,
workInProgress,
);
}
bubbleProperties
功能:fiber属性subtreeFlags, childLanes冒泡
实现:
subtreeFlags合并children的flags和subtreeFlagschildLanes合并children的lane和childLane
每个fiber都有其子树的subtreeFlags, childLanes
CommitRoot
将 fiber 树,渲染并且执行相关阶段工作。
- 处理
useEffect,uesLayoutEffect - 处理
class中getSnapshotBeforeUpdate,componentDidMount,componentDidUpdate,componentWillUnmount - 赋值
ref - 依次执行(
this.setState,ReactDOM.render) 的callback - 修改视图DOM。
Placement,Update,Deletion。
逻辑:
- 思路:
- 每个阶段都遍历
root.finishedWork- 是
render阶段完成构建的新fibet树。 - 值其实是
root.current.alternate
- 是
- 每次DFS fiber树,执行相关阶段work
- 性能优化:
subtreeFlags与此阶段相关的Flags对比为NoFlags则跳过此子树
- 每个阶段都遍历
处理useEffect -- 注意!!! 调度,下一个宏任务执行
scheduleCallback(flushPassiveEffects)- 调度执行
useEffect的destroy和create - 先destroy --
commitPassiveUnmountEffects - 在create --
commitPassiveMountEffects
- 调度执行
scheduleCallback(NormalSchedulerPriority, () => {
// 下个宏任务执行 处理useEffect 先执行destory,在create
flushPassiveEffects();
return null;
});
BeforMutation 阶段 -- 页面变动前 -- commitBeforeMutationEffects
- 功能:
- DFS fiber树,执行
getSnapshotBeforeUpdate
- DFS fiber树,执行
- 逻辑:
commitBeforeMutationEffects_begincommitBeforeMutationEffects_completecommitBeforeMutationEffectsOnFiber- 执行
commitBeforeMutationEffects - 处理
Snapshot,即getSnapshotBeforeUpdate。暂时无其他操作
- 执行
**Mutation**** 阶段** -- 页面变动中 --commitMutationEffects- 功能:
- DFS fiber树,处理
DeletePlcamentUpdate
- DFS fiber树,处理
- 逻辑:
commitMutationEffects_begin- 先处理被删除的fiber
- 若
fiber.deletions存在,则循环Delete每一项fiber- 注意:被删除的fiber,不在
finishedFiberTree中,只在returnFiber.deletions中 commitDeletioncommitNestedUnmounts- FunctionComponent :
layoutEffect destroy - ClassComponent:
componentWillUnmount - HostConpment: 清空
ref
- FunctionComponent :
detachFiberMutation- fiber,alternate return 置空
- 注意:被删除的fiber,不在
- 若
commitMutationEffects_completecommitMutationEffectsOnFiber- 判断
flags执行work-
ContentReset- 清空文本
-
Ref- 清空ref. layout会重新赋值
-
Visibility -
PlcamentcommitPlacementstateNode插入宿主
-
UpdatecommitWork- FunctionComponent:
layoutEffect destroy - HostComponent: 更新属性
- commitUpdate updateQueue
- 处理Children是单文本节点的优化
- HostText: 更新文本
- FunctionComponent:
-
- 判断
- 先处理被删除的fiber
- 功能:
function commitMutationEffects_begin(root: FiberRoot) {
while (nextEffect !== null) {
const fiber = nextEffect;
const deletions = fiber.deletions;
// deletions的fiber不存在finishedWork fiber树中,
// 因为在diff时不会被复用
if (deletions !== null) {
for (let i = 0; i < deletions.length; i++) {
const childToDelete = deletions[i];
// dfs 马上删除的fiber
// function : effect destroy
// class: componentWillUnmount
// host: 清除ref
// 然后卸载stateNode
commitDeletion(root, childToDelete, fiber);
}
}
const child = fiber.child;
// 性能优化: 若subtreeFlags无任务,则直接处理fiber,跳过子树,向上 "归",
if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {
nextEffect = child;
} else {
// 跳过无任务子树
// 无任务子树 或则 叶子节点
commitMutationEffects_complete(root);
}
}
}
function commitMutationEffects_complete(root: FiberRoot) {
while (nextEffect !== null) {
const fiber = nextEffect;
commitMutationEffectsOnFiber(fiber, root);
// 切换sibling
const sibling = fiber.sibling;
if (sibling !== null) {
nextEffect = sibling;
return;
}
// 切换 return
nextEffect = fiber.return;
}
}
function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {
const flags = finishedWork.flags;
if (flags & ContentReset) {
// 清空文本
commitResetTextContent(finishedWork);
}
if (flags & Ref) {
const current = finishedWork.alternate;
// 清空ref
if (current !== null) {
commitDetachRef(current);
}
}
// 新功能 先跳过
if (flags & Visibility) {}
const primaryFlags = flags & (Placement | Update | Hydrating);
outer: switch (primaryFlags) {
case Placement: {
// DOM插入 若有flags ContentReset则重置文本
commitPlacement(finishedWork);
finishedWork.flags &= ~Placement;
break;
}
case PlacementAndUpdate: {
commitPlacement(finishedWork);
finishedWork.flags &= ~Placement;
const current = finishedWork.alternate;
// 更新
// layoutEffect destroy
// hostComponent 更新属性
// hostText 更新文本
commitWork(current, finishedWork);
break;
}
case Update: {
const current = finishedWork.alternate;
commitWork(current, finishedWork);
break;
}
}
}
- root.current = finishedWork;
- 变动完,切换树
- 为什么在此处切换?
- 在此之前,旧
fiber树工作要依赖- eg:
mutation阶段中的componentWillUnmount是要依赖旧fiber树的,所以不切换
- eg:
- 之后
layout阶段,eg:componentDidMount和componentDidUpdate是要依赖于新fiber树,所以切换fiber树
- 在此之前,旧
Layout 阶段 -- 页面变动后 -- commitLayoutEffects
- 功能:
- DFS fiber树,处理
componentDidMount、componentDidUpdate、layoutEffect create、ref- 执行class的setState的callback
- DFS fiber树,处理
- 逻辑:
commitLayoutEffects_begin- 处理
OffscreenComponent
- 处理
commitLayoutMountEffects_completecommitLayoutEffectOnFibercommitHookEffectListMount- Function:
layoutEffect create - Class:
componentDidUpdate/componentDidMount- 判断curren 区分mount / update
- 执行
this.setState的callback -- commitUpdateQueue
- HostComponent: Renderer --
commitMount- Renderer可能会需要执行任务
- Function:
- commitAttachRef
- 更新ref
// 同相似Mutation的dfs
function commitLayoutEffectOnFiber(
finishedRoot: FiberRoot,
current: Fiber | null,
finishedWork: Fiber,
committedLanes: Lanes,
): void {
if ((finishedWork.flags & LayoutMask) !== NoFlags) {
switch (finishedWork.tag) {
case FunctionComponent: {
// layoutEffect create
commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);
break;
}
case ClassComponent: {
const instance = finishedWork.stateNode;
if (finishedWork.flags & Update) {
if (current === null) {
// 生命周期 componentDidMount
instance.componentDidMount();
} else {
const prevProps =
finishedWork.elementType === finishedWork.type
? current.memoizedProps
: resolveDefaultProps(
finishedWork.type,
current.memoizedProps,
);
const prevState = current.memoizedState;
// 生命周期componentDidUpdate
instance.componentDidUpdate(
prevProps,
prevState,
instance.__reactInternalSnapshotBeforeUpdate,
);
}
}
const updateQueue = (finishedWork.updateQueue: any);
if (updateQueue !== null) {
// this.setState的callback 队列
commitUpdateQueue(finishedWork, updateQueue, instance);
}
break;
}
case HostRoot: {
const updateQueue: UpdateQueue<*,
> | null = (finishedWork.updateQueue: any);
if (updateQueue !== null) {
let instance = null;
if (finishedWork.child !== null) {
switch (finishedWork.child.tag) {
case HostComponent:
instance = getPublicInstance(finishedWork.child.stateNode);
break;
case ClassComponent:
instance = finishedWork.child.stateNode;
break;
}
}
commitUpdateQueue(finishedWork, updateQueue, instance);
}
break;
}
case HostComponent: {
const instance: Instance = finishedWork.stateNode;
if (current === null && finishedWork.flags & Update) {
const type = finishedWork.type;
const props = finishedWork.memoizedProps;
// mount后执行,react-dom会执行focus
commitMount(instance, type, props, finishedWork);
}
break;
}
}
if (finishedWork.flags & Ref) {
// 执行ref
commitAttachRef(finishedWork);
}
}
commit阶段可能产生新的任务,进行处理。ensureRootIsScheduledflushSyncCallbacks
useEffect 与 useLayoutEffect
| 阶段 | useEffect | useLayoutEffect |
|---|---|---|
| beforeMutation | 无 | 无 |
| mutation | 无 | 执行destory(销毁函数) |
| layout | 无 | 执行create(useLayoutEffect) |
| 下一个宏任务 | 执行flushPassiveEffects,即依次执行destory,create | 无 |
useLayoutEffect是同步执行 useEffect是commit后,异步执行