JSX 是 JavaScript 的一种语法扩展,它让你可以在 JavaScript 文件中编写类似 HTML 的标记。虽然编写组件还有其他方式,但大多数 React 开发者更喜欢 JSX 的简洁性,而且大多数代码库都在使用它。
You will learn
- 为什么 React 会把标记和渲染逻辑混合在一起
- JSX 与 HTML 有什么不同
- 如何使用 JSX 显示信息
JSX:将标记放入 JavaScript 中
Web 是建立在 HTML、CSS 和 JavaScript 之上的。多年来,网页开发者一直把内容放在 HTML 中,把设计放在 CSS 中,把逻辑放在 JavaScript 中——通常还分散在不同的文件里!内容在 HTML 中被标记出来,而页面逻辑则单独存在于 JavaScript 中:


HTML


JavaScript
但随着 Web 变得越来越交互化,逻辑越来越多地决定了内容。JavaScript 开始负责 HTML!这就是为什么 在 React 中,渲染逻辑和标记会一起存在于同一个地方——组件中。


Sidebar.js React 组件


Form.js React 组件
将按钮的渲染逻辑和标记放在一起,可以确保它们在每次编辑时都保持同步。相反,彼此无关的细节,例如按钮的标记和侧边栏的标记,会彼此隔离,从而让单独修改它们中的任意一个都更安全。
每个 React 组件都是一个 JavaScript 函数,可能包含一些 React 会渲染到浏览器中的标记。React 组件使用一种名为 JSX 的语法扩展来表示这些标记。JSX 看起来很像 HTML,但它更严格一些,并且可以显示动态信息。理解这一点的最好方法,是把一些 HTML 标记转换成 JSX 标记。
将 HTML 转换为 JSX
假设你有一些(完全有效的)HTML:
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
<li>Invent new traffic lights
<li>Rehearse a movie scene
<li>Improve the spectrum technology
</ul>而你想把它放进你的组件中:
export default function TodoList() {
return (
// ???
)
}如果你原样复制并粘贴,它将无法工作:
export default function TodoList() { return ( // 这样不完全行! <h1>Hedy Lamarr's Todos</h1> <img src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg" alt="Hedy Lamarr" class="photo" > <ul> <li>Invent new traffic lights <li>Rehearse a movie scene <li>Improve the spectrum technology </ul>
这是因为 JSX 更严格,并且比 HTML 多一些规则!如果你阅读上面的错误信息,它们会引导你修复标记;或者你也可以按照下面的指南来做。
JSX 的规则
1. 返回单个根元素
要从组件中返回多个元素,请用一个单独的父标签把它们包裹起来。
例如,你可以使用 <div>:
<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</div>如果你不想在标记中额外添加一个 <div>,也可以改写为 <> 和 </>:
<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</>这个空标签称为 Fragment. Fragment 允许你将内容分组,而不会在浏览器的 HTML 树中留下任何痕迹。
Deep Dive
JSX 看起来像 HTML,但在底层它会被转换成普通的 JavaScript 对象。你不能在不把它们包装到数组中的情况下从函数中返回两个对象。这也解释了为什么你不能在不把两个 JSX 标签包裹到另一个标签或 Fragment 中的情况下返回它们。
2. 关闭所有标签
JSX 要求标签必须显式闭合:像 <img> 这样的自闭合标签必须写成 <img />,而像 <li>oranges 这样的包裹标签必须写成 <li>oranges</li>。
下面是 Hedy Lamarr 的图片和列表项闭合后的样子:
<>
<img
src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
/>
<ul>
<li>Invent new traffic lights</li>
<li>Rehearse a movie scene</li>
<li>Improve the spectrum technology</li>
</ul>
</>3. 大多数东西都要用 camelCase!
JSX 会变成 JavaScript,而在 JSX 中编写的属性会成为 JavaScript 对象的键。在你自己的组件中,你经常会想把这些属性读入变量中。但 JavaScript 对变量名有一些限制。例如,变量名不能包含连字符,也不能是像 class 这样的保留字。
这就是为什么在 React 中,许多 HTML 和 SVG 属性都使用 camelCase 编写。例如,不是使用 stroke-width,而是使用 strokeWidth。由于 class 是保留字,在 React 中你要改用 className,这个名称来源于 对应的 DOM 属性:
<img
src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>你可以在 DOM 组件 props 列表中找到所有这些属性。 如果你写错了,也不用担心——React 会在 浏览器控制台 中打印一条可能的更正信息。
专业提示:使用 JSX 转换器
把现有标记中的所有这些属性都转换过来可能会很繁琐!我们建议使用一个 转换器 来把你现有的 HTML 和 SVG 翻译成 JSX。转换器在实践中非常有用,但理解其原理仍然很值得,这样你就能自如地自己编写 JSX。
以下是最终结果:
export default function TodoList() { return ( <> <h1>Hedy Lamarr's Todos</h1> <img src="https://react.dev/images/docs/scientists/yXOvdOSs.jpg" alt="Hedy Lamarr" className="photo" /> <ul> <li>Invent new traffic lights</li> <li>Rehearse a movie scene</li> <li>Improve the spectrum technology</li> </ul> </> ); }
Recap
现在你知道为什么会有 JSX,以及如何在组件中使用它了:
- React 组件把渲染逻辑和标记组合在一起,因为它们彼此相关。
- JSX 与 HTML 类似,但有一些不同。如果需要,你可以使用 转换器。
- 错误信息通常会指引你朝正确的方向去修复标记。