把 UI 看作树
渲染树表达了什么关系?
- 渲染树: 表示一次渲染中 React 组件的父子关系,根组件在顶部,未再渲染其他组件的节点是叶子;
- 模型范围: 这里讨论组件关系,不把每个 HTML 标签都当成组件节点;它不等同于浏览器 DOM 树;
- 动态结构: 条件渲染会改变树的分支,同一应用在不同状态下可能得到不同渲染树;
App
├── SearchBox
└── Results
├── Result
└── Result
渲染树如何帮助定位状态与性能问题?
- 数据归属: 需要共享状态的组件可以沿树向上寻找共同祖先,具体流程见 React 思维;
- 更新范围: 观察更新由哪个组件发起、传播到哪些子组件,再使用性能工具核对实际成本;
- 组合注意: 接收 children 的容器不一定导入或创建该内容,不能仅凭 import 关系推断渲染父子关系;
模块依赖树表达了什么关系?
- 依赖关系: 模块之间通过 import 引用其他模块,节点是文件模块,边表示导入关系;
- 非组件模块: 工具函数、数据文件和样式也可参与依赖关系,不必都是 React 组件;
- 打包用途: 构建工具沿依赖关系收集代码,因此它影响 bundle 内容与加载成本;
App.js
├── SearchBox.js
├── Results.js
│ └── Result.js
└── data.js
为什么不能用一种树代替另一种树?
- 渲染问题: “哪个组件显示在谁里面”需要观察本次渲染结构;
- 加载问题: “为什么这段代码进入 bundle”需要沿模块导入关系追踪;
- 服务端边界: 客户端模块依赖边界也不等于渲染树边界,见服务端组件笔记;