首先,我们本次的切入文件如下
代码语言: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节点的属性值,下边的函数里我删掉了一段优化性能以及另一方便测试使用的代码
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为什么这么受欢迎了嘛,一眼就知道下一步看哪里) 那么可以看到
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
类似的,后边我们才会具体接触到这些参数