React 17原理

React 17原理

两大工作循环

在执行reconcile的时候,并不会先去构造fiber,而是先去schedule调度中心申请 task,即把更新需求转换成一个task;然后调度中心执行task,构造fiber然后commitRoot

reconciler 运作流程

  1. 输入: 暴露api函数(如: scheduleUpdateOnFiber), 供给其他包(如react包)调用.
  2. 注册调度任务: 与调度中心(scheduler包)交互, 注册调度任务task, 等待任务回调.
  3. 执行任务回调: 在内存中构造出fiber树, 同时与与渲染器(react-dom)交互, 在内存中创建出与fiber对应的DOM节点.
    1. 如果本次渲染被中断,会返回一个新的performConcurrentWorkOnRoot,等待下次执行
  4. 输出: 与渲染器(react-dom)交互, 渲染DOM节点.

在最新稳定版v17.0.2中, 可中断渲染虽然实现, 但是并没有在稳定版暴露出 api. 只能安装 alpha 版本才能体验该特性.

Fiber树构造

探寻阶段 beginWork

  1. 根据 ReactElement对象创建所有的fiber节点, 最终构造出fiber树形结构(设置returnsibling指针)
  2. 设置fiber.flags(二进制形式变量, 用来标记 fiber节点 的增,删,改状态, 等待completeWork阶段处理)
  3. 设置fiber.stateNode局部状态(如Class类型节点: fiber.stateNode=new Class())

回溯阶段 completeWork

  1. 调用completeWork
    • fiber节点(tag=HostComponent, HostText)创建 DOM 实例, 设置fiber.stateNode局部状态(如tag=HostComponent, HostText节点: fiber.stateNode 指向这个 DOM 实例).
    • 为 DOM 节点设置属性, 绑定事件(这里先说明有这个步骤, 详细的事件处理流程, 在合成事件原理中详细说明).
    • 设置fiber.flags标记
  2. 把当前 fiber 对象的副作用队列(firstEffectlastEffect)添加到父节点的副作用队列之后, 更新父节点的firstEffectlastEffect指针.
  3. 识别beginWork阶段设置的fiber.flags, 判断当前 fiber 是否有副作用(增,删,改), 如果有, 需要将当前 fiber 加入到父节点的effects队列, 等待commit阶段处理.

Hooks

  • 其中hook.queuefiber.updateQueue虽然都是update环形链表, 尽管update对象的数据结构与处理方式都高度相似, 但是这 2 个队列中的update对象是完全独立的. hook.queue只作用于hook对象的状态维护, 切勿与fiber.updateQueue混淆.

fiber.memoizedState 表示对应hook

hook.memoizedState : 保存内存中的局部状态并且还有更新的quene

hooks链表和ClassInstance一样,用于保存局部状态,里面的state变更都会引起重新渲染,但是各子组件需要保存自己的state状态

参考