React- JSX 到 Fiber(纯概念之间的关系)

644 阅读3分钟

极力推荐:卡松大佬-React技术揭秘

1. Jsx 到 Fiber

JSX 一种描述当前组件内容的数据结构,理解为骨架

Fiber 一种异步可中断架构,Fiber并不是计算机术语中的新名词,他的中文翻译叫做纤程,与进程(Process)、线程(Thread)、协程(Coroutine)同为程序执行过程。在很多文章中将纤程理解为协程的一种实现。在JS中,协程的实现便是Generator。所以,我们可以将纤程(Fiber)、协程(Generator)理解为代数效应思想在JS中的体现。

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

  • 作为静态的数据结构来说,每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件...)、对应的DOM节点等信息。
  • 作为动态的工作单元来说,每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新...)

Fiber数据结构包含如下信息

大致分为4类:
1.静态数据结构属性
2.用于连接其他Fiber节点形成Fiber树属性
3.动态工作单元属性(更新相关)
4.调度优先级属性
数据结构如下:
function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // 作为静态数据结构的属性
  this.tag = tag; // Fiber对应组件类型 function、class、host
  this.key = key; // key属性
  this.elementType = null; // 大部分情况同type,某些情况不同,被React.memo包裹等
  this.type = null; // 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName
  this.stateNode = null; //Fiber对应的真实DOM节点

  // 用于连接其他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;
}

Jsx与Fiber关系

  • 概述:jsx 映射出 静态结构Fiber(保存了该组件的类型(函数组件/类组件/原生组件...)、对应的DOM节点等信息); 动态结构Fiber动态的工作单元来说,保存了本次更新中该组件改变的状态、优先级、要执行的工作(需要被删除/被插入页面中/被更新...)等; 静态 + 动态组成完整的Fiber结构

  • 过程如下:

  1. jsx 通过 @babel/plugin-transform-react-jsx 将其转换成 createElement(),函数名由babel配置决定

  2. createElement()函数内部调用ReactElement(),返回React Element(该对象包含了jsx编写的属性值、事件、className等信息)

  3. mount时,Reconciler(协调器)根据JSX描述的信息 生成对应的 Fiber节点(包含优先级信息、状态、被打上的标记)

  4. update时,Reconciler将根据更新后对应JSX生成对应的workInProgress Fiber 与 之前保存的 current Fiber对比patch,打上标记交给renderer,然后将workInProgress Fiber 变成current Fiber。workInProgress fiber的创建可以复用current Fiber树对应的节点数据,使用双缓存即在内存中进行。

    export function createElement(type, config, children) {
          let propName;

          const props = {};

          let key = null;
          let ref = null;
          let self = null;
          let source = null;

          if (config != null) {
            // 将 config 处理后赋值给 props
            // ...省略
          }

          const childrenLength = arguments.length - 2;
          // 处理 children,会被赋值给props.children
          // ...省略

          // 处理 defaultProps
          // ...省略

      return ReactElement(
        type,
        key,
        ref,
        self,
        source,
        ReactCurrentOwner.current,
        props,
      );
    }

    const ReactElement = function(type, key, ref, self, source, owner, props) {
      const element = {
        // 标记这是个 React Element
        $$typeof: REACT_ELEMENT_TYPE,

        type: type,
        key: key,
        ref: ref,
        props: props,
        _owner: owner,
      };

      return element;
    }; 

★努力方向:渲染细节(render阶段、commit阶段)、Scheduler调度器!!!

React更新流程.png