React 理念

113 阅读4分钟

React 15

  • Reconciler 协调器-----找出变化的组件
  • Renderder 渲染器-----同步渲染变化的组件

缺点

更新是同步不可中断的,用户会感知到页面的变化,一旦更新中单,会给用户造成不好的体验

React 16

  • Scheduler 调度器-----调度任务的优先级,高优先级任务优先进入Reconciler
  • Reconciler 协调器-----找出变化的组件,打上标识
  • Renderder 渲染器-----异步可中断更新

Scheduler

调度器的功能并不是React独有或者最早提出的,其实在部分浏览器已经具备了调度器的功能

requestIdleCallback

React 为什么放弃使用requestIdleCallback

  • 浏览器兼容问题
  • 触发频率不稳定,受很多因素影响。比如当我们的浏览器切换tab后,之前tab注册的requestIdleCallback触发的频率会变得很低
  • 没有调度优先级

Reconciler Renderder

React 16 是将Reconciler 协调器进行了重构

老版本React 是通过递归来更新dom的 ReconcilerRenderer 交替工作,会同步的更新DOM,给用户感知上的变化

新版本的React ReconcilerRenderer不再是交替工作,Reconciler会将需要更新的组件,打上标识,统一移交给Renderer,最后由渲染器统一渲染,这个过程的变化都是在js中,视图不会发生任何变化,用户是无法感知的。

这就是新版本 React 16 的异步可中断更新

Fiber

React内部实现的一套状态更新机制。支持任务不同优先级,可中断与恢复,并且恢复后可以复用之前的中间状态

其中每个任务更新单元为React Element对应的Fiber节点

虚拟DOM === Fiber

Fiber的出现

新版本的React 实现了异步可中断更新,那么老版本的不可中断更新的虚拟DOM结构已经不能满足新版本React对于虚拟DOM的需求,就出现了一种全新的架构---Fiber

Fiber的含义

  • 架构: 老版本的React Reconciler 递归更新,被称为stack Reconciler 新版本的React Reconciler 异步可中断更新,被称为Fiber Reconciler

  • 静态数据结构: 每个Fiber节点 保存了当前组件的类型,对应的DOM信息

  • 动态数据结构: 每个Fiber节点 保存了本次更新改变的状态, 要执行的工作(增删改查)

Fiber的结构

function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // 作为静态数据结构的属性
  this.tag = tag;          // 组件的类型??? 函数,类
  this.key = key;          // key值
  this.elementType = null; //  
  this.type = null;
  this.stateNode = null;   // 真实DOM节点

  // 用于连接其他Fiber节点形成Fiber树
  this.return = null;  // 指向父节点的Fiber
  this.child = null;   // 指向子节点的Fiber
  this.sibling = null; // 指向同级的Fiber
  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树

React 中会存在两棵Fiber

  • current Fiber 当前展示在页面中的Fiber 树(虚拟DOM树)

  • workInPorgress Fiber 正在内存中构建的Fiber树 (触发更新时就会创建)


currentFiber.alternate === workInProgressFiber;
workInProgressFiber.alternate === currentFiber;

React 通过 current 指针切换不同的Fiber树rootFiber间切换来完成current Fiber树指向的切换

更新流程


function App() {
  const [num, add] = useState(0);
  return (
    <p onClick={() => add(num + 1)}>{num}</p>
  )
}

ReactDOM.render(<App/>, document.getElementById('root'));

首次执行, 会创建出fiberRootrootFiber

fiberRoot 代表了整个应用的根节点

rootFiber 代表了当前组件的根节点

每个组件都会拥有自己的rootFiber,但是fiberRoot只会有一个

第一次更新

image.png

初次创建 rootFiber下没有任何的Fiber节点

由于是第一次render 所以在内存中创建workInPorgress Fiber

创建对应的DOM元素 通过return child sibling 进行连接,形成最新的workInPorgress Fiber

只有currentFiberrootFiber 通过 alternate 连接了 workInPorgress FiberrootFiber

更新阶段

image.png

render的过程中,在内存中创建workInPorgress Fiber

新旧的Fiber 节点 通过alternate 连接

根据记录的更新信息,进行相对应的功能

render阶段结束,进入commmit阶段,用workInPorgress Fiber 替换 current Fiber 形成最新的current Fiber