Skip to content

⚠️ Important Notice

This post was last updated on: which was . Please pay attention to its timelines.

状态更新流程

在reconciler中会通过beginWorkcompleteUnitOfWork来生成一个新的Fiber树,其中经历了状态更新流程diff才生成的树形结构,最后交给renderer渲染器进行渲染

概览

React使用中可以通过以下几种方式来触发更新(忽略class版本的):

  • ReactDOM.render/ReactDOM.createElement().render:这是初始化React,也是会触发更新的。
  • useState:底层和useReducer调用的是一个东西,可以看做是一个特殊的useReducer
  • useReducer

当触发更新状态之后,会在当前组件对应的Fiber节点的updateQueue属性上插入一个Update对象,Update对象上记录了Fiber节点收集到的更新。然后从当前的Fiber节点,一直回溯到最顶端的HostRoot节点。

之后从HostRoot节点开始对Fiber树进行dfs,即上文的Scheduler+Reconciler过程。

Update对象

上面说到有两种方式来触发更新,按照这两种更新方式Update对象可以分为两类:

  • render对应的一种Update对象结构
  • Hook对应的另一种Update对象结构

renderUpdate对象

这个Update对象是由createUpdate方法创建的:

js
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也是有类型的,是通过下面的工厂函数来创建的:

js
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,基于此来计算更新后的state

  • firstBaseUpdate、lastBaseUpdate更新前该fiber节点就已经存在的update对象。链表形式存在,以fistBaseUpdate为链表头,lastBaseUpdate为链表尾。

    更新前就存在是某些优先级较低,所以上一次render被跳过了。

  • shared.pending:更新时,生成的update对象会保存在这里形成单向环形链表

  • effects:如果update.callback有值就会保存在这里。

举例说明

上一次更新: