React的fiber体系

132 阅读3分钟

fiber体系介绍

React中的Virtual DOM体系,叫做fiber体系。 fiber是一个Virtual DOM节点,存储了当前节点的信息(自身的信息,父级节点指针,子节点指针,兄弟节点指针等等)。

fiber的类型

如下图,fiber有很多种类型,在执行更新的时候,只有组件类型的fiber会通过执行渲染函数产生新的React Element。

export const FunctionComponent = 0; // 对应函数组件
export const ClassComponent = 1; // 对应类组件
export const IndeterminateComponent = 2; // 初始化的时候不知道是函数组件还是类组件
export const HostRoot = 3; // RootFiber可以理解为根节点,通过reactDom.render()产生的根元素
export const HostPortal = 4; 
export const HostComponent = 5;// DOM元素比如<div>
export const HostText = 6;// 文本节点
export const Fragment = 7;// 对应<React.Fragment>
export const Mode = 8;// 对应<React.StrictMode>
export const ContextConsumer = 9;// 对应<Context.Consumer>
export const ContextProvider = 10;// 对应<Context.Provider>
export const ForwardRef = 11;// 对应<React.forwardRef>
export const Profiler = 12;// 对应<React.Profiler/>
export const SuspenseComponent = 13;// 对应<Suspense>
export const MemoComponent = 14;// 对应<React.memo>返回的组件

创建fiberNode的方法

export function FiberNode (tag, pendingProps, key, mode) {
  this.tag = tag;// 说明是什么类型的fiber
  this.key = key;// key调和子节点的时候用到
  this.type = null;// 如果是DOM元素,指的是元素类型,如div, 如果是组件,指的是组件对应的类或者函数
  this.stateNode = null;// 指向对应的真实元素,类组件指向组件实例
  this.return = null;//指向父级fiber
  this.child = null;// 指向子级fiber
  this.sibling = null;// 指向兄弟fiber
  this.index = 0;// 索引
  this.ref = null;//ref指向,函数或者ref对象
  this.pendingProps = pendingProps;// 在一次更新中,代表重新创建Element生成的props
  this.memoizedProps = null;// 记录上一次更新完毕后的props
  this.updateQueue = null;// 记录更新队列
  this.memoizedState = null;// 类组件保存State信息,函数组件保存Hooks信息,DOM元素为null
  this.dependencies = null;// Context依赖项
  this.mode = mode;// 描述fiber树的模式,比如concurrentMode模式

  // V16老版本
  this.effectTag = null;// effect标签,用于收集effectList
  this.nextEffect = null;// 指向下一个effect
  this.firstEffect = null;// 第一个Effect
  this.lastEffect = null;// 最后一个effect
  this.expirationTime = NoWork;// 过期时间,判断任务是否过期,在ReactV17 及以上版本用lane表示

  // V17版本
  this.flags = NoFlags;// 类似于effectTag
  this.subtreeFlags = NoFlags;// 当前fiber的子代fiber是否有flags
  this.lanes = NoLanes; // 是否有更新标志
  this.childLanes = NoLanes; // Children是否有更新标志

  // 
  this.alternate = null;// 双缓存树,指向缓存的fiber。更新阶段,两个树互相交替
}

Element、fiber、DOM三者之间的关系

fiber、Element、真实DOM之间的关系.png

fiber体系出现的背景及目的

在React V15以及之前的版本,React对于 Virtual DOM是采用递归的方式进行遍历更新的。

一次更新,就会从应用根部递归更新,递归一旦开始,中途无法中断,随着项目越来越复杂,层级越来越深,导致更新的时间越来越长,给前端交互上的体验就是卡顿。

React V16为了解决卡顿问题,引入了fiber体系

fiber树的构建

双缓存树的设计

在内存中构建并替换的技术叫做双缓存。比如canvas在绘制动画的时候,如果上一帧计算量比较大,导致清除上一帧的画面到渲染出最新画面有比较长的时间间隔,就会出现白屏。如果提前在内存中绘制好,直接替换渲染好的帧,就能给用户更好的体验。

React用workInProgress(内存中的树)和current(正在视图中渲染的树)来实现更新逻辑。

React的更新流程

  1. 在更新对应fiber的lane,向上回溯更新父级链上的childLanes
  2. 从根节点开始,一直向下查找定位到发生变化的Fiber节点
  3. 重新执行组件得到新的Element,对比oldProps和newProps,对比lane和renderLane判断是否要更新,是否是需要更新的节点
  4. 对新生成的Element和对应的oldFiber进行diff,并创建新的Fiber(可能会复用oldFiber),变动的类型用flag字段做标记,更新标志如Placement(插入元素)、Update(更新元素)
  5. 更新DOM
  6. 浏览器绘制

123.png

Element和fiber的区别: Element是用数组来存储子元素的,而fiber是用child + sibling的对象结构存储的。