https://react.iamkasong.com/

疑问

  • fiber是什么?
    • 是React16以后的虚拟DOM
    • 是可中断状态更新机制的核心
  • React16的改动
    • 添加了Scheduler调度器
    • 改写了原本一口气递归的协调器,改为了基于fiber的可中断的协调器
  • JSX和Fiber节点是同一个东西么?
  • React Component、React Element是同一个东西么,他们和JSX有什么关系?

    书摘&心得

  • 为了【快速响应】,需要将同步的更新变为可中断的异步更新

    1 前置知识

    1.1 React15

  • 架构可以分为两层:

    • Reconciler(协调器)—— 负责找出变化的组件
      • 转换虚拟DOM、对比、更新、渲染
      • 数据保存在递归调用栈中,所以被称为stack Reconciler
    • Renderer(渲染器)—— 负责将变化的组件渲染到页面
      • React支持跨平台,所以不同平台有不同的Renderer
        • 浏览器环境渲染的Renderer —— ReactDOM
  • 缺点

    • Reconciler递归更新子组件,更新一旦开始,中途就无法中断。

      1.2 React16

  • 在15的基础上,新增了Scheduler(调度器)

    • Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
    • Reconciler(协调器)——更新工作从递归变成了可以中断的循环过程
      • Reconciler会为变化的虚拟DOM打上代表增/删/更新的标记
      • 只有当所有组件都完成Reconciler的工作,才会统一交给Renderer
      • Reconciler内部采用了Fiber的架构,被称为Fiber Reconciler
    • Renderer(渲染器)
      • 根据Reconciler为虚拟DOM打的标记,同步执行对应的DOM操作。

        1.3 fiber

  • React Fiber可以理解为:

    • React内部实现的一套状态更新机制。
    • 支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态。
  • 虚拟DOM在React中有个正式的称呼——Fiber

    1.3.1 fiber的角色

    【作为架构】
    每个Fiber节点有个对应的React element,多个Fiber节点是如何连接形成树呢?靠如下三个属性:

    1. // 指向父级Fiber节点
    2. this.return = null;
    3. // 指向子Fiber节点
    4. this.child = null;
    5. // 指向右边第一个兄弟Fiber节点
    6. this.sibling = null;

    【作为静态的数据结构】

  • 每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息。

    1. // Fiber对应组件的类型 Function/Class/Host...
    2. this.tag = tag;
    3. // key属性
    4. this.key = key;
    5. // 大部分情况同type,某些情况不同,比如FunctionComponent使用React.memo包裹
    6. this.elementType = null;
    7. // 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName
    8. this.type = null;
    9. // Fiber对应的真实DOM节点
    10. this.stateNode = null;

    【作为动态的工作单元】

  • 每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)

    1.3.2 fiber的双缓存

  • 在内存中构建并直接替换的技术叫做双缓存

  • 当前屏幕上显示内容对应的Fiber树称为current Fiber树,正在内存中构建的Fiber树称为workInProgress Fiber树。
  • DOM的更新过程就是fiber树的构建与替换过程

    1.4 深入理解JSX

  • JSX在编译时会被Babel编译为React.createElement方法

    • 这也是为什么在每个使用JSX的JS文件中,你必须显式的声明
    • 但是React17无需这么做,转化函数改为从React的package中引入新入口函数调用,由编译器使用
  • 与React Element
    • 所有JSX在运行时的返回结果(即React.createElement()的返回值)都是React Element。
  • 与React Component
    • React Component是一种React Element,可以通过type区分
  • 与fiber
    • 在组件mount时,Reconciler根据JSX描述的组件内容生成组件对应的Fiber节点
    • 在update时,Reconciler将JSX与Fiber节点保存的数据对比,生成组件对应的Fiber节点,并根据对比结果为Fiber节点打上标记

      2 render阶段