首先,本篇文章大部分是属于个人的理解和学习总结,新手可以参考,大牛可以帮忙指正。
关于React版本
从15开始学习到现在,如果单从生命周期来讲,变化还是挺大,下面看一下15、16生命周期的变化:
-
React15的生命周期
-
React16的生命周期(官方解释)
对比可以看出来很多生命周期或者已经转成不安全弃用,或者变更新的生命周期。
其变化的核心就是React16引入了调度器(Scheduler),按照任务优先级去执行,优先级高的先进入协调器(Reconciler);而协调器(Reconciler:负责找出变化的组件)也进行了重构,引入了Fiber的概念。
React15架构可以分为两层:
- Reconciler(协调器)—— 负责找出变化的组件
- Renderer(渲染器)—— 负责将变化的组件渲染到页面上
React16架构可以分为三层:
- Scheduler(调度器)—— 调度任务的优先级,高优任务优先进入Reconciler
- Reconciler(协调器)—— 负责找出变化的组件
- Renderer(渲染器)—— 负责将变化的组件渲染到页面上
Fiber
上边已经说到React16引入了调度器,重构了协调器,那么这一变化的目的是什么?
目的是解决CPU的瓶颈,将老的同步更新的架构变为异步可中断更新。更新在执行过程中可能会被打断(浏览器时间分片用尽或有更高优任务插队),当可以继续执行时恢复之前执行的中间状态。
Fiber就可以理解成是React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态。
实际上Fiber包含三层含义:
1)作为架构来说,之前React15的Reconciler采用递归的方式执行,数据保存在递归调用栈中,所以被称为stackReconciler。React16的Reconciler基于Fiber节点实现,被称为Fiber Reconciler。
2)作为静态的数据结构来说,每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息。
3)作为动态的工作单元来说,每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)。
Fiber结构
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// 作为静态数据结构的属性
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
// 用于连接其他Fiber节点形成Fiber树
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
// 作为动态的工作单元的属性
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
// 调度优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;
// 指向该fiber在另一次更新时对应的fiber
this.alternate = null;
}
从上边的结构也可以看出,Fiber节点既包含了组件相关信息,又包含了部分状态变更的信息,以及调度的优先级等信息。Fiber节点保存了DOM节点,Fiber树对应DOM树。而更新DOM树的核心就是Fiber的双缓存树。
双缓存Fiber树
双缓存树Fiber树分别是:current Fiber树(对应当前页面显示的内容)和workInprogress Fiber树(内存中构建的树)。
当页面发生变化时,会构建workInprogress Fiber树,两个fiber树的节点通过alternate来连接,然后对比节点变化,由workInprogress Fiber树替换current Fiber树。(具体过程可以看React技术揭秘)