React将其呈现树的内部表示形式存储为React Fiber(v16.0+)。它为我们渲染的每个JSX元素创建一个Fiber节点,然后将其连接到其父节点、子节点和同级节点,以创建完整的树形结构。
我们将这个连接的树形结构称为Fiber树。
简单来说,你在React调试器的组件选项卡中找到关于它的大部分信息。
需要注意的是,在Fiber树中,每个父节点都包含一个指向其第一个(最左侧)子节点的链接,但不包含整个子节点数组。子节点反过来链接到它的兄弟节点。
可以将其视为一个链接列表,或者正式地称为左孩子右兄弟树。
这是一个简化的表示(右图),它们还包含属性,以便引用回父级(return属性)和状态/属性(memoizedState,memoizedProps)。它还会引用回实际对应的DOM节点。
前期准备
需要注意的是,内部的Fiber数据结构可能会随着时间而发生变化。即使在v16引入Fiber之后,这些规则在小版本中也可能略有改变。这在React 16.9(react-dom同样如此)中同样存在。
本文记录了我在探索Fiber结构时所能理解的一切。Nitin关于自定义渲染器的文章详细介绍了它(请查找“Fiber”部分)。将其视为一篇有趣的阅读材料,了解一些有趣的知识,并可能基于此制作Demo项目,但不是简单的应用到生产。
Fiber的类型
该结构保持不变,但某些属性(的类型)的值会根据正在呈现的元素略有不同。
- 1、类组件
- 2、函数组件
- 3、固有元素(例如JSX中的)
- 4、文本元素(例如JSX中的
Hello- 仅为文本部分)
对于每种类型,我们将查看调试器视图与内部对象结构的比较,并解释结构的各个部分。
稍后我将尝试添加一些“自己尝试”链接。固有元素和文本元素
重要属性:
- type → 元素的类型,例如“div”
- child、sibling → 连接到这些的fiber节点。如果不存在,则为null。
- return → 连接到父节点的链接。
- stateNode → 链接到在DOM(浏览器)中创建的div。这是从fiber树到DOM树的唯一链接。
文本元素类似,只是它们没有子元素或类型(两者都为null)。stateNode链接回DOM中的TextNode。
函数组件
Button是个函数组件
属性:- type → 函数组件的引用
- stateNode → 对于此类型,它始终为null
类组件
Task是个类组件
属性: - type → 类组件的引用
- stateNode → stateNode链接回其对应的类实例。每当我们渲染一个类时,React在内部创建这个类的实例。实际上,你可以访问该实例的this,并且可以检查实例属性、调用方法等。
技巧:在React调试器中选择节点(针对类组件)会将其实例引用设置为$r。在控制台中尝试。
寻找根结点
通常,查找根fiber节点是第一步。你需要找到它,以便遍历并到达其他fiber节点。
有两种方法可以得到它:
- A. 从根DOM节点 -读取 rootNode._reactRootContainer._internalRoot.current
- B. 从ReactDOM.render的输出 -ReactDOM.render目前返回根fiber节点。
稍后可能会更改,渲染也可能变成异步。
应用案例
这是最困难的部分。希望提供一些指引,说明可能存在的用例(尽管它们有些牵强)。这将引导读者在他们的上下文中提出一些用例建议。
A. 查找并突出显示组件渲染的DOM节点
- 演示1-https://jsfiddle.net/bendtherules/ox35khu9/81/
这里有多种查找策略可行-按名称查找(检查type.name),按组件查找(函数/类 - 使用type进行检查)或按引用(对于类组件,请使用stateNode进行检查)。 - 您甚至可以引入类似于CSS的选择器来选择组件,然后有效地选择其中的DOM节点。
演示2-https://codesandbox.io/s/css-like-selector-d8u65
B. 测试选择DOM节点 - 这只是前面一点的扩展。
通常,在端到端测试期间,我们通过类名和ID选择DOM节点。要想得到正确的选择器稍微有些麻烦:- a. 由于 class 名称会被混淆,所以要得到正确的选择器稍微有些麻烦,
- b. 如果某些元素不需要自定义样式,则类名经常会丢失(更像是在React中不需要),
- c. 所有这些都必须考虑到整个应用程序的范围。
如果你能够:
a. 首先缩小范围,只定位到你想查看的组件
b. 然后编写一个仅在该组件内部起作用的选择器注意:这在与测试框架集成时稍微有些棘手,因为按ID/类查找是内置的 locateStrategy 和webdriver规范的一部分。添加新的可能需要一些思考。
C. 遍历Fiber节点 —
你可以遍历这些节点并将它们序列化并记录到控制台中。相关链接
- Resq
- Resq是webdriver.io的一部分,用于按名称选择组件的现有项目。
- 具有一些缺点,例如强制将所选节点和子树转换为其自己的简化结构。
- React-fiber-traverse
- 遍历工具,可以查找节点并使用类似于 CSS 的选择器进行匹配。
- 目前还不太稳定。
未来的思考
这也涉及到自定义渲染器。你可以通过 internalInstanceHandle 访问相同的对象。Nitin关于自定义渲染器的文章详细解释了这一点。在这里我们只谈到了React-DOM作为渲染器,但是如果其他渲染器以某种方式允许访问根节点,那么这个结构应该是类似的。
它也可以通过调试器访问。结束语
React Fiber 是一个有趣的实现细节需要了解。由于其内部性质和可能的破坏性变化,投入时间了解它可能并没有太多意义。但它也是一种方便的方式,可以在组件之间“查找” React 树中的某些信息。它在开发和生产构建中都可以工作。
也许为更复杂的用例添加自定义调试器是可行的方法。
- 4、文本元素(例如JSX中的