v19.2Latest

将你的 UI 理解为树

你的 React 应用正在成型,许多组件相互嵌套。React 是如何跟踪你的应用组件结构的呢?

React 以及许多其他 UI 库将 UI 建模为树。将你的应用视为树有助于理解组件之间的关系。这种理解将帮助你调试未来的概念,如性能和状态管理。

你将学习
  • React 如何“看待”组件结构
  • 什么是渲染树及其用途
  • 什么是模块依赖树及其用途

你的 UI 作为树

树是项目之间的关系模型。UI 通常使用树结构来表示。例如,浏览器使用树结构来建模 HTML(DOM)和 CSS(CSSOM)。移动平台也使用树来表示其视图层次结构。

一个水平排列、包含三个部分的图表。第一部分有三个垂直堆叠的矩形,标签分别为'组件 A'、'组件 B'和'组件 C'。过渡到下一个窗格的箭头上方有 React 徽标,并标有'React'。中间部分包含一个组件树,根节点标为'A',两个子节点标为'B'和'C'。下一部分再次通过一个上方带有 React 徽标并标有'React DOM'的箭头过渡。第三部分也是最后一部分是一个浏览器线框图,包含一棵 8 个节点的树,其中仅高亮显示了中间部分子树的一个子集。一个水平排列、包含三个部分的图表。第一部分有三个垂直堆叠的矩形,标签分别为'组件 A'、'组件 B'和'组件 C'。过渡到下一个窗格的箭头上方有 React 徽标,并标有'React'。中间部分包含一个组件树,根节点标为'A',两个子节点标为'B'和'C'。下一部分再次通过一个上方带有 React 徽标并标有'React DOM'的箭头过渡。第三部分也是最后一部分是一个浏览器线框图,包含一棵 8 个节点的树,其中仅高亮显示了中间部分子树的一个子集。

React 从你的组件创建一个 UI 树。在这个例子中,UI 树随后被用来渲染到 DOM。

与浏览器和移动平台类似,React 也使用树结构来管理和建模 React 应用中组件之间的关系。这些树是理解数据如何在 React 应用中流动以及如何优化渲染和应用大小的有用工具。

渲染树

组件的一个主要特性是能够组合其他组件。当我们嵌套组件时,我们就有了父组件和子组件的概念,其中每个父组件本身可能是另一个组件的子组件。

当我们渲染一个 React 应用时,我们可以将这种关系建模为一棵树,称为渲染树。

这是一个渲染励志名言的 React 应用。

包含五个节点的树状图。每个节点代表一个组件。树的根节点是 App,从它延伸出两条箭头指向'InspirationGenerator'和'FancyText'。箭头标有'渲染'字样。'InspirationGenerator'节点也有两条箭头指向节点'FancyText'和'Copyright'。包含五个节点的树状图。每个节点代表一个组件。树的根节点是 App,从它延伸出两条箭头指向'InspirationGenerator'和'FancyText'。箭头标有'渲染'字样。'InspirationGenerator'节点也有两条箭头指向节点'FancyText'和'Copyright'。

React 创建一个渲染树,一个由已渲染组件组成的 UI 树。

根据示例应用,我们可以构建出上面的渲染树。

树由节点组成,每个节点代表一个组件。AppFancyTextCopyright等等,都是我们树中的节点。

React 渲染树的根节点是应用的根组件。在这个例子中,根组件是App,它是 React 渲染的第一个组件。树中的每个箭头都从父组件指向子组件。

Deep Dive
渲染树中的 HTML 标签在哪里?

渲染树表示 React 应用程序的单个渲染过程。通过条件渲染,父组件可能会根据传递的数据渲染不同的子组件。

我们可以更新应用程序,以有条件地渲染励志名言或颜色。

包含六个节点的树状图。树的顶部节点标记为'App',有两条箭头线延伸至标记为'InspirationGenerator'和'FancyText'的节点。箭头线为实线,并标有'渲染'字样。'InspirationGenerator'节点还有三条箭头线。指向'FancyText'和'Color'节点的箭头线为虚线,并标有'渲染?'。最后一条箭头线指向标记为'Copyright'的节点,为实线并标有'渲染'。包含六个节点的树状图。树的顶部节点标记为'App',有两条箭头线延伸至标记为'InspirationGenerator'和'FancyText'的节点。箭头线为实线,并标有'渲染'字样。'InspirationGenerator'节点还有三条箭头线。指向'FancyText'和'Color'节点的箭头线为虚线,并标有'渲染?'。最后一条箭头线指向标记为'Copyright'的节点,为实线并标有'渲染'。

通过条件渲染,在不同的渲染过程中,渲染树可能会渲染不同的组件。

在这个例子中,根据 inspiration.type的值,我们可能会渲染<FancyText><Color>。每次渲染过程的渲染树可能都不同。

尽管渲染树在不同的渲染过程中可能不同,但这些树通常有助于识别 React 应用程序中的顶层叶子组件。顶层组件是离根组件最近的组件,影响其下所有组件的渲染性能,并且通常包含最复杂的逻辑。叶子组件位于树的底部,没有子组件,并且经常被重新渲染。

识别这些组件类别对于理解应用程序的数据流和性能非常有用。

模块依赖树

React 应用中另一种可以用树来建模的关系是应用的模块依赖关系。当我们拆分组件和逻辑到单独的文件时,我们创建了JS 模块,在其中我们可以导出组件、函数或常量。

模块依赖树中的每个节点都是一个模块,每个分支代表该模块中的一个import 语句。

如果我们以前面的 Inspirations 应用为例,我们可以构建一个模块依赖树,或简称为依赖树。

一个包含七个节点的树状图。每个节点都标有一个模块名称。树的顶层节点标为'App.js'。有三条箭头指向模块'InspirationGenerator.js'、'FancyText.js'和'Copyright.js',箭头标有'imports'。从'InspirationGenerator.js'节点出发,有三条箭头延伸至三个模块:'FancyText.js'、'Color.js'和'inspirations.js'。箭头标有'imports'。一个包含七个节点的树状图。每个节点都标有一个模块名称。树的顶层节点标为'App.js'。有三条箭头指向模块'InspirationGenerator.js'、'FancyText.js'和'Copyright.js',箭头标有'imports'。从'InspirationGenerator.js'节点出发,有三条箭头延伸至三个模块:'FancyText.js'、'Color.js'和'inspirations.js'。箭头标有'imports'。

Inspirations 应用的模块依赖树。

树的根节点是根模块,也称为入口文件。它通常是包含根组件的模块。

与同一应用的渲染树相比,结构相似,但存在一些显著差异:

  • 构成树的节点代表模块,而非组件。
  • 非组件模块,例如 inspirations.js,也会在此树中表示。渲染树仅封装组件。
  • Copyright.js 出现在 App.js下方,但在渲染树中,组件Copyright 作为 InspirationGenerator的子组件出现。这是因为InspirationGenerator接受 JSX 作为子属性,因此它将Copyright渲染为子组件,但并未导入该模块。

依赖树有助于确定运行 React 应用需要哪些模块。在为生产环境构建 React 应用时,通常会有一个构建步骤,将所有必要的 JavaScript 打包以交付给客户端。负责此工作的工具称为打包器,打包器会使用依赖树来确定应包含哪些模块。

随着应用的增长,打包体积通常也会增加。过大的打包体积对于客户端下载和运行来说代价高昂。过大的打包体积可能会延迟用户界面的绘制时间。了解应用的依赖树有助于调试这些问题。

回顾

  • 树是表示实体之间关系的常见方式。它们通常用于对用户界面进行建模。
  • 渲染树表示单次渲染中 React 组件之间的嵌套关系。
  • 在条件渲染下,渲染树可能在不同的渲染中发生变化。使用不同的属性值,组件可能会渲染不同的子组件。
  • 渲染树有助于识别顶层组件和叶子组件。顶层组件影响其下所有组件的渲染性能,而叶子组件通常会被频繁重新渲染。识别它们对于理解和调试渲染性能非常有用。
  • 依赖树表示 React 应用中的模块依赖关系。
  • 构建工具使用依赖树来打包交付应用所需的代码。
  • 依赖树有助于调试因打包体积过大而导致的绘制延迟问题,并为优化打包代码提供机会。