🎉干货满满,React设计原理(一):藏在源码里的紧箍咒🎉
💡 相关阅读
文章首发公众号: 萌萌哒草头将军,最近关注有🎁,欢迎关注
最近在努力研究React
源码,发现它并没有我之前想象的那么难理解。
虽然源码里面有一些概念就像一座五指山困住了桀骜不驯的孙悟空。
但如果你理解了下面的几个概念,读懂react源码就不是难事了。
Fiber
相关变量命名
💎 第一座山:我们已经知道从v16.8
开始,React
进入了fiber
架构时代,将不可中断的递归改进为可中断的递归。
fiber
架构主要的工作是创建fiber tree
,然后在合适的时机将这棵树渲染在屏幕上.
所以围绕着fiber
,源码里出现了一堆带着fiber
的变量。
FiberNode
🚗 首先,在源码中,FiberNode
是个构造函数,它包含了许多属性。
function FiberNode(
this: $FlowFixMe,
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance
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.refCleanup = 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;
}
这些属性可以根据FiberNode
的不同身份进行划分。
FiberNode
在React
中通常有三种不同的身份:
- 👉 作为架构的一环
作为架构的一环,多个FiberNode
作为基本节点构成fiber tree
。
此时,它的相关属性如下:
// Fiber
// 指向父节点
this.return = null;
// 指向第一个子节点
this.child = null;
// 指向右边兄弟节点
this.sibling = null;
this.index = 0;
- 👉 作为数据的一环
作为数据的一环,它保存了基本的React
元素信息。
// Instance
// 对应组件的类型,可以是class、function等
this.tag = tag;
// 组件的key
this.key = key;
// 和type类似的属性
this.elementType = null;
// 根据tag的不同,可以是calss、function、tagName(div、input等原始的标签)
this.type = null;
// FiberNode对应的元素
this.stateNode = null;
这里说明一下React
元素:
React
元素可以是<div>Hello!</div>
基本HTML
元素,也可以是<App />
这样的组件,App
是个类组件或者函数组件等。
- 👉 作为调度的一环
作为调度的一环,它提供了调度时的一些依据。
// render相关
this.flags = NoFlags;
this.subtreeFlags = NoFlags;
this.deletions = null;
// 优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;
// 缓存相关
this.alternate = null;
fiberNode
🚗 前面说过,FiberNode
是fiber tree
最小单元。而React
元素被编译之后的VNode
都成为FiberNode
构造函数的实例,源码中实例都用fiber
或者workInProgress
表示。
HostRootFiber
🚗 HostRootFiber
是源码里使用createHostRootFiber
创建的Fiber
根节点,它包含整棵组件树的信息。对应的是如下代码:
<body>
<div id="app"></div>
<div id="app2"></div>
<div id="app3"></div>
</body>
React
允许你创建最多个HostRootFiber
,也就是说,你可以有多个上述的挂载节点。
rootFiber
🚗 源码里通过createHostRootFiber
的实例在作为参数时,偶尔也会使用rootFiber
表示。
FiberRootNode
🚗 FiberRootNode
表示应用根节点。它保存着应用的状态信息和组件信息。它的数据结构如下:
function FiberRootNode(
this: $FlowFixMe,
containerInfo: any,
// $FlowFixMe[missing-local-annot]
tag,
hydrate: any,
identifierPrefix: any,
onRecoverableError: any,
) {
this.tag = tag;
// 表示应用程序的容器元素,即组件树的根节点
// 它一般是一个 DOM 元素,用来承载整个组件树的渲染结果。
this.containerInfo = containerInfo;
// 表示当前应用程序中待处理的子树列表
this.pendingChildren = null;
// 表示当前渲染的 Fiber 树的根节点,指向 HootRootFiber
this.current = null;
// 网络请求优化用的属性
this.pingCache = null;
// 表示最近一次渲染完成的 Fiber 树的根节点
// React 在进行组件更新时,会创建一个新的 Fiber 树
// 并将它与旧的 Fiber 树进行比较,找出需要更新的部分
// 然后进行更新。当更新完成后,最近一次渲染的结果
// 会存储在 `finishedWork` 属性中
this.finishedWork = null;
// 表示当前应用程序的上下文
this.context = null;
// 表示当前应用程序的挂起上下文
// 在 React 中,当组件的上下文发生变化时,
// React 会将新的上下文信息存储在 `pendingContext` 中
// 待下一次更新时再进行处理。
this.pendingContext = null;
// 当组件完成更新后的回调函数
this.callbackNode = null;
// 表示下一次更新的过期时间
this.expirationTimes = createLaneMap(NoTimestamp);
// 优先级相关的属性
this.pendingLanes = NoLanes;
this.suspendedLanes = NoLanes;
this.pingedLanes = NoLanes;
this.expiredLanes = NoLanes;
this.mutableReadLanes = NoLanes;
this.finishedLanes = NoLanes;
//....
}
通常状况下,FiberRootNode
和HootRootFiber
是一一对应的关系。
FiberRootNode
是单例对象,每个应用程序只会有一个实例,如果一个页面有多个React
应用,那么会有多个实例。
fiberRootNode
🚗fiberRootNode
是createFiberRoot
的返回值类型。即FiberRootNode
实例。源码里用fiberRoot
表示。
💎 总结
在Fiber
架构中,FiberNode
实例fiber
既是fiber tree
的基本数据结构单元,记录元素节点的信息,也是组件根节点的数据单元,记录整个组件树的信息,同时也会为调度相关的工作提供依据;
FiberRootNode
的实例fiberRoot
是应用根节点的数据单元,包含整个应用的状态信息和租价信息。它和HootRootFiber
实例rootFiber
是一一对应关系