第二章 JSX
JSX 基础
1. JSX 表达式
- 只支持 JavaScript 表达式:JSX 中只能嵌入 JavaScript 表达式,不能使用语句(如
if
、for
等)。 createRoot
的限制:createRoot
只能指定body
的子节点作为根容器(root)。- 根容器与根元素的区别:
- 根容器:React 应用的挂载点(如
document.getElementById('root')
)。 - 根元素:JSX 中的最外层元素(如
<div>
或<React.Fragment>
)。
- 根容器:React 应用的挂载点(如
2. React.Fragment
<></>
:空文档标记标签,提供了根元素,但不会在 DOM 中占据具体位置。- 应用场景:当需要返回多个元素但不想添加额外的 DOM 节点时使用。
3. Mustache 语法 {}
- 原始值:
- 支持
string
和number
,其他数据类型(如boolean
、null
、undefined
)渲染为空。
- 支持
- 对象:
- 支持数组渲染,数组会被
flat
后依次渲染。 - 不支持普通对象渲染(如
{ key: value }
),会抛出错误。
- 支持数组渲染,数组会被
- JSX VDOM 渲染:
- JSX 会被转换为虚拟 DOM(VDOM),最终渲染为真实 DOM。
style
行内样式:- 在
style
中可以使用 JavaScript 表达式,如三目运算符。
- 在
4. map
操作与 key
map
操作:通过map
遍历数据模型(Model)时,需要为循环元素的根元素添加key
。key
的作用:帮助 React 识别哪些元素发生了变化,从而优化 DOM Diff 算法。key
的选择:通常使用index
或数据项的唯一 ID。
- 示例:jsx
const items = [{ id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }]; const list = items.map(item => <li key={item.id}>{item.name}</li>);
5. 密集数组与稀疏数组
- 密集数组:每一项都有值(即使是
null
),可以通过new Array(n).fill(null)
创建。 - 稀疏数组:每一项都是
empty
,无法直接遍历。 - 应用场景:当需要创建固定长度的占位符时,使用密集数组。
JSX 机制
1. JSX 的本质
- 语法转换:JSX 本质上是语法糖,会被 Babel 转换为
React.createElement
调用。 - 流程:
- 创建 VDOM:JSX 被转换为虚拟 DOM(VDOM)。
- 转换为真实 DOM:VDOM 被渲染为真实 DOM。
2. 渲染过程
- 第一次渲染:
- 缓存 VDOM。
- 直接将 VDOM 转换为真实 DOM。
- 后续更新:
- 通过 Diff 算法比对新旧 VDOM,计算出差异(PATCH 包)。
- 只更新差异部分(PATCH 补丁包),避免全量更新。
3. 技术延伸
- 虚拟 DOM 的优势:
- 性能优化:减少直接操作真实 DOM 的次数,避免重绘和回流。
- 跨平台:VDOM 可以渲染到不同平台(如 Web、Native)。
- 类比:
- VDOM 类似于 Git 的差异比较:只更新变化的部分,而不是全量替换。
容易忽略的问题
1. key
的重要性
- 如果没有为列表项添加
key
,React 会默认使用index
,这可能导致性能问题或渲染错误。 - 最佳实践:始终使用唯一标识符作为
key
。
2. JSX 中的表达式限制
- JSX 中只能使用表达式,不能使用语句。如果需要条件渲染,可以使用三元运算符或逻辑与(
&&
)。
3. 稀疏数组的陷阱
- 稀疏数组无法直接遍历,可能导致意外行为。建议使用密集数组替代。
总结
- JSX 是 React 的核心语法,本质上是 JavaScript 的语法糖,最终会被转换为
React.createElement
调用。 - 虚拟 DOM 是 React 性能优化的关键,通过 Diff 算法减少不必要的 DOM 操作。
key
的作用不可忽视,它帮助 React 高效地更新列表项。- 密集数组与稀疏数组的区别:密集数组更适合用于占位符场景。