React源码阅读(二):Fiber结构实现

2022-08-12 11:34:42 浏览数 (1)

首先,我们本次的切入文件如下

代码语言:javascript复制
packages/react-reconciler/src/ReactFiber.new.js

虚拟DOM;我们都知道虚拟DOM,但是React中它其实有个正式的称呼Fiber

目前我了解到的,在React15及以前,Reconciler采用递归的方式创建虚拟DOM,递归过程是不能中断的。如果组件树的层级很深,递归会占用线程很多时间,造成卡顿。

而在React16之后,Fiber架构使得更新被转变为了异步的可中断更新

阅读起来~FiberNode

从1-112行似乎都和正文没有太大关系,更多的是各种导入以及环境变量的设定,我们从114行开始

函数FiberNode的参数共四个,由于文件上边包含了@flow,所以这里可以使用类型注解。

同时结合下边大量this.xxx,显然这是一个构造函数,定义了Fiber节点的属性值,下边的函数里我删掉了一段优化性能以及另一方便测试使用的代码

代码语言:javascript复制
function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // 实例变量,从字面意思也应该可以看出这里保存了tag、key、type、state类似这样的有很强实际意义的属性
  this.tag = tag;
  this.key = key;
  this.elementType = null;
  this.type = null;
  this.stateNode = null;

  // 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;

  // Effects
  this.flags = NoFlags;
  this.subtreeFlags = NoFlags;
  this.deletions = null;

  this.lanes = NoLanes;
  this.childLanes = NoLanes;

  this.alternate = null;
}

那么我试着按照官方空格分段一点点看看,第一部分还是比较容易理解的

实例数据/静态数据

代码语言:javascript复制
// 实例变量,从字面意思也应该可以看出这里保存了tag、key、type、state类似这样的有很强实际意义的属性
  this.tag = tag;
  this.key = key;
  this.elementType = null;
  this.type = null;
  this.stateNode = null;

这一部分,保存了组件的相关信息,其中各个属性的含义又分别代表:

  • tag 注意到tag在下边很多地方都能看到,而通过注解我们知道这是一个WorkTag类型(所以知道TypeScript为什么这么受欢迎了嘛,一眼就知道下一步看哪里) 那么可以看到

代码语言:javascript复制
export type WorkTag =
  | 0
  | 1
  ...
  | 23
  | 24;

export const FunctionComponent = 0;
//函数式组件
export const ClassComponent = 1;
//类组件
export const IndeterminateComponent = 2;
...
export const LegacyHiddenComponent = 23;
export const CacheComponent = 24;

嗷,我们似乎一下子看到了不得了的东西。其实这里是意思是,0对应函数式组件、1对应类组件、2对应不确定组件(我不知道这个噶)......这样往下去对应。这里包含的显然是React的组件类型,于是我们本次阅读源码的收获之一到手

TODO: React 的25种组件类型

  • key 略,和你想的那个key就是一个意思
  • elementType 我们从本段其实看不到太多,往下翻。

疑似和type没有太大差别......嗯不太理解了查查资料

  • type 对于 FunctionComponent,指函数本身,对于ClassComponent,指class,对于HostComponent,指DOM节点tagName
  • stateNode 这个好说,这里代表的的是真实节点

return、child、sibling、index

这几个属性用于生成Fiber Tree结构

代码语言:javascript复制
// 指向上一级级Fiber节点
this.return = null;
// 指向下一级Fiber节点
this.child = null;
// 指向右边第一个兄弟Fiber节点
this.sibling = null;
//同级节点中自己是第几个
this.index=0;

而Fiber Tree结构我们举个例子伐

代码语言:javascript复制
function App(){
    return (
        <div>
        	<p>Hello</p>
            <div>
            	<span>Fiber</span>
            </div>
        </div>)
}

最终要生成这么一颗Fiber树,而这其实就对应我们所说的虚拟DOM树,首先列出节点

我还没有很清楚DOM和Fiber之间的详细关系,暂时不加入关系图,剩下的连接起来。如下:

BUT......为什么不用parent来命名return

更多数据*from kasong

代码语言:javascript复制
// 看起来颇为爆炸,保存本次更新造成的状态改变相关信息
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;

this.mode = mode;

// 保存本次更新会造成的DOM操作
this.effectTag = NoEffect;
this.nextEffect = null;

this.firstEffect = null;
this.lastEffect = null;

// 调度优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;

这一块有较多关联,包括更新过程中的一些参数、调度优先级,可以先从字面意义理解;

从pendingProps、memoizeProps的字面意思,这些都是和父组件传入的props相关的参数,保存的也是对应pending、memoized这些状态下的props

类似的,后边我们才会具体接触到这些参数

0 人点赞