状态更新流程
在reconciler中会通过
beginWork和completeUnitOfWork来生成一个新的Fiber树,其中经历了状态更新流程、diff才生成的树形结构,最后交给renderer渲染器进行渲染
概览
在React使用中可以通过以下几种方式来触发更新(忽略class版本的):
ReactDOM.render/ReactDOM.createElement().render:这是初始化React,也是会触发更新的。useState:底层和useReducer调用的是一个东西,可以看做是一个特殊的useReduceruseReducer
当触发更新状态之后,会在当前组件对应的Fiber节点的updateQueue属性上插入一个Update对象,Update对象上记录了Fiber节点收集到的更新。然后从当前的Fiber节点,一直回溯到最顶端的HostRoot节点。
之后从HostRoot节点开始对Fiber树进行dfs,即上文的Scheduler+Reconciler过程。
Update对象
上面说到有两种方式来触发更新,按照这两种更新方式Update对象可以分为两类:
render对应的一种Update对象结构Hook对应的另一种Update对象结构
render的Update对象
这个Update对象是由createUpdate方法创建的:
export function createUpdate(eventTime: number, lane: Lane): Update<*> {
const update: Update<*> = {
eventTime,
lane,
tag: UpdateState,
payload: null,
callback: null,
// 重点关注这个,与其他Update对象形成链表结构。
next: null,
};
return update;
}可以看到该对象上有个next属性,Fiber节点上多个Update对象会通过该属性连成链表结构保存到fiber.updateQueue上。
多个Update对象,在批量更新等情况会出现,即多次执行更新函数
因为对象是保存在fiber节点上的,双缓存会同时存在两颗Fiber树,所以也会同时存在两个updateQueue。
updateQueue类型
updateQueue也是有类型的,是通过下面的工厂函数来创建的:
export function initializeUpdateQueue<State>(fiber: Fiber): void {
const queue: UpdateQueue<State> = {
baseState: fiber.memoizedState,
firstBaseUpdate: null,
lastBaseUpdate: null,
shared: {
pending: null,
interleaved: null,
lanes: NoLanes,
},
effects: null,
};
fiber.updateQueue = queue;
}可以看到最后挂载到了fiber.updateQueue上。
其他属性介绍如下:
baseState更新前该fiber节点的state,基于此来计算更新后的statefirstBaseUpdate、lastBaseUpdate更新前该fiber节点就已经存在的update对象。链表形式存在,以fistBaseUpdate为链表头,lastBaseUpdate为链表尾。更新前就存在是某些优先级较低,所以上一次
render被跳过了。shared.pending:更新时,生成的update对象会保存在这里形成单向环形链表effects:如果update.callback有值就会保存在这里。