🎉干货满满,React设计原理(一):藏在源码里的紧箍咒🎉

简介: 🎉干货满满,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的不同身份进行划分。

FiberNodeReact中通常有三种不同的身份:

  • 👉 作为架构的一环

作为架构的一环,多个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元素可以是

Hello!

基本HTML元素,也可以是这样的组件,App是个类组件或者函数组件等。

  • 👉 作为调度的一环

作为调度的一环,它提供了调度时的一些依据。

// render相关
this.flags = NoFlags;
this.subtreeFlags = NoFlags;
this.deletions = null;
// 优先级相关
this.lanes = NoLanes;
this.childLanes = NoLanes;
// 缓存相关
this.alternate = null;

🚗 fiberNode

前面说过,FiberNodefiber 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;
  //....
}

通常状况下,FiberRootNodeHootRootFiber是一一对应的关系。

FiberRootNode是单例对象,每个应用程序只会有一个实例,如果一个页面有多个React应用,那么会有多个实例。

🚗fiberRootNode

fiberRootNodecreateFiberRoot的返回值类型。即FiberRootNode实例。源码里用fiberRoot表示。

💎 总结

Fiber架构中,FiberNode实例fiber既是fiber tree的基本数据结构单元,记录元素节点的信息,也是组件根节点的数据单元,记录整个组件树的信息,同时也会为调度相关的工作提供依据;

FiberRootNode的实例fiberRoot是应用根节点的数据单元,包含整个应用的状态信息和租价信息。它和HootRootFiber实例rootFiber是一一对应关系。


相关文章
|
5月前
|
算法 前端开发 JavaScript
React的diff算法原理
React的diff算法原理
110 0
|
5月前
|
JSON 缓存 前端开发
【React】React原理面试题集锦
本文集合一些React的原理面试题,方便读者以后面试查漏补缺。作者给出自认为可以让面试官满意的简易答案,如果想要了解更深刻,可以点击链接查看对应的详细博文。在此对链接中的博文作者非常感谢🙏。
119 0
|
16天前
|
存储 前端开发 测试技术
React Hooks 的工作原理
【10月更文挑战第1天】
|
16天前
|
移动开发 JSON 数据可视化
精选八款包括可视化CMS,jquery可视化表单,vue可视化拖拉,react可视化源码
精选八款包括可视化CMS,jquery可视化表单,vue可视化拖拉,react可视化源码
36 0
|
2月前
|
前端开发 算法 JavaScript
React原理之Diff算法
【8月更文挑战第24天】
|
2月前
|
前端开发 JavaScript 算法
如何学习react原理
【8月更文挑战第9天】 如何学习react原理
41 6
|
2月前
|
开发者 安全 UED
JSF事件监听器:解锁动态界面的秘密武器,你真的知道如何驾驭它吗?
【8月更文挑战第31天】在构建动态用户界面时,事件监听器是实现组件间通信和响应用户操作的关键机制。JavaServer Faces (JSF) 提供了完整的事件模型,通过自定义事件监听器扩展组件行为。本文详细介绍如何在 JSF 应用中创建和使用事件监听器,提升应用的交互性和响应能力。
31 0
|
2月前
|
前端开发 Java UED
瞬间变身高手!JSF 与 Ajax 强强联手,打造极致用户体验的富客户端应用,让你的应用焕然一新!
【8月更文挑战第31天】JavaServer Faces (JSF) 是 Java EE 标准的一部分,常用于构建企业级 Web 应用。传统 JSF 应用采用全页面刷新方式,可能影响用户体验。通过集成 Ajax 技术,可以显著提升应用的响应速度和交互性。本文详细介绍如何在 JSF 应用中使用 Ajax 构建富客户端应用,并通过具体示例展示 Ajax 在 JSF 中的应用。首先,确保安装 JDK 和支持 Java EE 的应用服务器(如 Apache Tomcat 或 WildFly)。
40 0
|
2月前
|
缓存 JavaScript 前端开发
【React生态进阶】React与Redux完美结合:从原理到实践全面解析构建大规模应用的最佳策略与技巧分享!
【8月更文挑战第31天】React 与 Redux 的结合解决了复杂状态管理的问题,提升了应用性能。本文详细介绍了在 React 应用中引入 Redux 的原因、步骤及最佳实践,包括安装配置、状态管理、性能优化等多方面内容,并提供了代码示例,帮助你构建高性能、易维护的大规模应用。
43 0
|
2月前
|
前端开发 JavaScript 中间件
【前端状态管理之道】React Context与Redux大对决:从原理到实践全面解析状态管理框架的选择与比较,帮你找到最适合的解决方案!
【8月更文挑战第31天】本文通过电子商务网站的具体案例,详细比较了React Context与Redux两种状态管理方案的优缺点。React Context作为轻量级API,适合小规模应用和少量状态共享,实现简单快捷。Redux则适用于大型复杂应用,具备严格的状态管理规则和丰富的社区支持,但配置较为繁琐。文章提供了两种方案的具体实现代码,并从适用场景、维护成本及社区支持三方面进行对比分析,帮助开发者根据项目需求选择最佳方案。
36 0