beginWork的实现
在 beginWork 中有很多针对 fiber 的操作,所以在正式看 beginWork 的流程之前,先研究一下 Fiber 的结构。
type Fiber = {|
// 表示Fiber的类型
tag: WorkTag,
// child 的唯一标识符
key: null | string,
// element.type 的值,用于在 diff 子项期间保留标识
elementType: any,
// 与 fiber 关联的函数或类
type: any,
// fiber 关联的局部状态
stateNode: any,
// 我们正在处理的东西的父对象。概念上与堆栈帧的返回地址相同。
return: Fiber | null,
// 用长子-兄弟链表表示法表示一棵Fiber树
child: Fiber | null,
sibling: Fiber | null,
index: number,
// 最后一个用于绑定本结点的 ref,不能绑定到函数式组件上。
ref:
| null
| (((handle: mixed) => void) & {_stringRef: ?string, ...})
| RefObject,
// 等待 Fiber 处理的 props
pendingProps: any,
memoizedProps: any, //用于创建产出的 props
// 状态更新和回调的队列
updateQueue: mixed,
// 用于创建输出的状态
memoizedState: any,
// fiber 的依赖项可能是 context 或 event
dependencies: Dependencies | null,
// 描述 fiber 和它的子树的性质的位域。比如 ConcurrentMode flag 表示子树默认情况下是异步的。当 fiber 被创建时,它的 mode 会继承父 fiber 的 mode,也可以在创建的时候添加更多的 flag,但是创建之后,在 fiber 的整个生命周期都不应该再被改变。
mode: TypeOfMode,
// Effect
flags: Flags,
subtreeFlags: Flags,
deletions: Array<Fiber> | null,
// 副作用 fiber 链表中当前 fiber 的 next 指针
nextEffect: Fiber | null,
// 副作用 fiber 链表的头指针
firstEffect: Fiber | null,
// 副作用 fiber 链表的尾指针
lastEffect: Fiber | null,
lanes: Lanes,
childLanes: Lanes,
// 这是 fiber 的更新合并后的版本
alternate: Fiber | null,
// 省略调试相关和 profiler 相关字段
|};
beginWork 逻辑
如果新旧 props 发生变化或者消费的 context 发生了改变,则 didReceiveUpdate = true
否则,调 checkScheduledUpdateOrContext 函数,如果返回值为 false 并且 workInProgress.flags & DidCapture) === NoFlags,则设置 didReceiveUpdate 为 false,调用attemptEarlyBailoutIfNoScheduledUpdate 并返回其返回值
根据 workInProgress.tag 的值调用不同的操作,其中函数组件的操作如下,关键是调用了 updateFunctionComponent 函数
PS:新 props 指 workInProgress.pendingProps,旧 props 指 current.memoizedProps,即便新旧 props 没有变化或者 context 没有改变,也不能立即得出 fiber 不需要更新的结论,因为如果第二次传递 error 或 suspense 边界,可能在 current 上不存在 work 的调度。所以需要调用 checkScheduledUpdateOrContext 进行检查。
updateFunctionComponent
function updateFunctionComponent (
current,
workInProgress,
Component,
nextProps: any,
renderLanes,
) {}
核心逻辑如下:
- 处理 context(调 getUnmaskedContext、getMaskedContext 和 prepareToReadContext),然后执行 renderWithHooks 函数。
- 如果 current 不为 null 且 didReceiveUpdate 为false,则执行 bailoutHooks 函数和 bailoutOnAlreadyFinishedWork 函数,并返回后者。
- 如果 getIsHydrating() 为 true,并且 checkDidRenderIdHook() 为 true,则调用 pushMaterializedTreeId(workInProgress) 函数
- 执行 reconcileChildren 函数 返回 workInProgress.child