React Fiber可以理解为:
React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态。
Fiber包含三层含义:
- 作为架构来说,之前
React15的Reconciler采用递归的方式执行,数据保存在递归调用栈中,所以被称为stack Reconciler。React16的Reconciler基于Fiber节点实现,被称为Fiber Reconciler。 - 作为静态的数据结构来说,每个
Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件...)、对应的DOM节点等信息。 - 作为动态的工作单元来说,每个
Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新...)
Fiber的工作原理或者Fiber是如何更新dom的?
我们在绘制一帧动画的时候,如果当前帧计算量比较大,那么清除上一帧动画到当前帧绘制画面会有较长时间的白屏出现,如果我们内存中绘制当前帧的动画,绘制完毕后直接用当前帧替换上一帧画面,由于省去了两帧替换间的计算时间,就不会出现从白屏。
React使用“双缓存”来完成Fiber树的构建与替换——对应着DOM树的创建与更新。
双缓存Fiber树
在React中最多会同时存在两棵Fiber树。
当前屏幕上显示内容对应的Fiber树称为current Fiber树,正在内存中构建的Fiber树称为workInProgress Fiber树。
React应用的根节点通过使current指针在不同Fiber树的rootFiber间切换来完成current Fiber树指向的切换。
即当workInProgress Fiber树构建完成交给Renderer渲染在页面上后,应用根节点的current指针指向workInProgress Fiber树,此时workInProgress Fiber树就变为current Fiber树。
每次状态更新都会产生新的workInProgress Fiber树,通过current与workInProgress的替换,完成DOM更新。
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;
}
组件mount时
-
首次执行
ReactDOM.render会创建fiberRootNode和rootFiber- 其中
fiberRootNode是整个应用的根节点,rootFiber是<App/>所在组件树的根节点。 - 之所以要区分
fiberRootNode与rootFiber,是因为在应用中我们可以多次调用ReactDOM.render渲染不同的组件树,他们会拥有不同的rootFiber。但是整个应用的根节点只有一个,那就是fiberRootNode。 fiberRootNode的current会指向当前页面上已渲染内容对应Fiber树,即current Fiber树。- 由于是首屏渲染,页面中还没有挂载任何
DOM,所以fiberRootNode.current指向的rootFiber没有任何子Fiber节点(即current Fiber树为空)。
- 其中
-
接下来进入
render阶段,根据组件返回的JSX在内存中依次创建Fiber节点并连接在一起构建Fiber树,被称为workInProgress Fiber树。- 在构建
workInProgress Fiber树时会尝试复用current Fiber树中已有的Fiber节点内的属性,在首屏渲染时只有rootFiber存在对应的current fiber(即rootFiber.alternate)。
- 在构建
-
更新完毕之后,
fiberRootNode的current指针指向workInProgress Fiber树使其变为current Fiber 树。
组件Update时
-
接下来我们点击
节点触发状态改变,这会开启一次新的render阶段并构建一棵新的workInProgress Fiber 树。和
mount时一样,workInProgress fiber的创建可以复用current Fiber树对应的节点数据。 -
workInProgress Fiber 树在render阶段完成构建后进入commit阶段渲染到页面上。渲染完毕后,workInProgress Fiber 树变为current Fiber 树。