React 源码讲解第 4 节- Fiber 对象

上一节 React 源码讲解第 2 节-入口 API 之 ReactDOM.render 讲到 render 函数的核心步骤。其中非常重要的一个环节就是创建 Fiber 对象 。本小节介绍 Fiber 对象的含义、类型以及具体包含哪些属性。

Fiber 的三层含义

  1. 作为架构来说,React 15 的 Reconciler (协调器)采用的是不可中断的递归 。所以被称为【stack Reconciler】,而 React 16 的 Reconciler (协调器)是基于 Fiber 实现的是可中断的循环。所以被称为【Fiber Reconciler】。
  2. 作为静态的数据结构来说,每一个 element 节点都有一个对应的 Fiber 对象,保存了该组件的类型以及 DOM 节点信息。
  3. 作为动态的工作单元来说,每一个 Fiber 节点保存了本次更新中该组件改变的状态、要执行的工作等(删除/插入/更新…)。

Fiber 的八种类型

export const FunctionComponent = 0;// 函数类型
export const ClassComponent = 1;// class 类型
export const IndeterminateComponent = 2; // 不确定类型;可能是class或function
export const HostRoot = 3; // 树的根
export const HostPortal = 4; // 一颗子树
export const HostComponent = 5; // 原生节点;根据环境而定,浏览器环境就是div等
export const HostText = 6; // 纯文本节点
export const Fragment = 7; // 节点片段

Fiber 数据结构

function FiberNode(tag, pendingProps, key, mode) {
    
    
  // Fiber 对应组件的类型 Function/class/ContextProvider
  this.tag = tag;
  // key属性
  this.key = key;
  //大部分情况同type,某些情况不同,比如 FunctionComponent 使用React.memo 包裹
  this.elementType = null;
  // 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指 DOM 节点的tagName
  this.type = null;
  // Fiber对应的真实DOM节点
  this.stateNode = null; 
  
  // 以下属性用于连接其他Fiber节点形成Fiber树。
  // 指向父Fiber节点
  this.return = null;
  //指向第一个子Fiber节点
  this.child = null;
  //指向右边第一个兄弟Fiber节点
  this.sibling = null;
  
  this.index = 0;
  // 获取真实节点的 DOM 属性
  this.ref = null;
  
  // 动态的工作单元属性。保存本次更新造成的状态改变相关信息
  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;
  this.dependencies = null;
  
  //开发模式
  this.mode = mode; // Effects
  
  // 保存本次更新会造成的DOM操作。比如删除,移动
  this.effectTag = NoEffect;
  this.nextEffect = null;
  this.firstEffect = null;
  this.lastEffect = null;
  
  // 调度优先级相关
  this.expirationTime = NoWork;
  this.childExpirationTime = NoWork;
  
  // 指向该fiber在另一次更新时对应的fiber,
  //用于链接新树和旧树;旧->新,新->旧
  this.alternate = null;

  {
    
    
    // Note: The following is done to avoid a v8 performance cliff.
    //
    // Initializing the fields below to smis and later updating them with
    // double values will cause Fibers to end up having separate shapes.
    // This behavior/bug has something to do with Object.preventExtension().
    // Fortunately this only impacts DEV builds.
    // Unfortunately it makes React unusably slow for some applications.
    // To work around this, initialize the fields below with doubles.
    //
    // Learn more about this here:
    // https://github.com/facebook/react/issues/14365
    // https://bugs.chromium.org/p/v8/issues/detail?id=8538
    this.actualDuration = Number.NaN;
    this.actualStartTime = Number.NaN;
    this.selfBaseDuration = Number.NaN;
    this.treeBaseDuration = Number.NaN; // It's okay to replace the initial doubles with smis after initialization.
    // This won't trigger the performance cliff mentioned above,
    // and it simplifies other profiler code (including DevTools).

    this.actualDuration = 0;
    this.actualStartTime = -1;
    this.selfBaseDuration = 0;
    this.treeBaseDuration = 0;
  } // This is normally DEV-only except www when it adds listeners.
  // TODO: remove the User Timing integration in favor of Root Events.


  {
    
    
    this._debugID = debugCounter++;
    this._debugIsCurrentlyTiming = false;
  }

  {
    
    
    this._debugSource = null;
    this._debugOwner = null;
    this._debugNeedsRemount = false;
    this._debugHookTypes = null;

    if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
    
    
      Object.preventExtensions(this);
    }
  }
}

开发模式

本源码讲解的是最新版本 React 16.13.1。到目前版本为止,内置的开发模式有如下几种。其中最常用的是严格模式 StrictMode。

export type TypeOfMode = number;
// 普通模式|Legacy模式,同步渲染,React15-16的生产环境用
export const NoMode = 0b0000;
// 严格模式,用来检测是否存在废弃API(会多次调用渲染阶段生命周期),React16-17开发环境使用
export const StrictMode = 0b0001;
// ConcurrentMode 模式的过渡版本
export const BlockingMode = 0b0010;
// 并发模式,异步渲染,React17的生产环境用
export const ConcurrentMode = 0b0100;
// 性能测试模式,用来检测哪里存在性能问题,React16-17开发环境使用
export const ProfileMode = 0b1000;

猜你喜欢

转载自blog.csdn.net/weixin_44135121/article/details/108723829