使用 JSX 编写标记

JSX 是 JavaScript 的一种语法扩展,允许你在 JavaScript 文件中编写类似 HTML 的标记。尽管还有其他方法可以编写组件,但大多数 React 开发人员更喜欢 JSX 的简洁性,而且大多数代码库都使用它。

你将学习

  • 为什么 React 要将标记与渲染逻辑混合在一起
  • JSX 与 HTML 有何不同
  • 如何使用 JSX 显示信息

JSX:将标记放入 JavaScript 中

Web 一直以来都是基于 HTML、CSS 和 JavaScript 构建的。多年来,Web 开发人员将内容放在 HTML 中,将设计放在 CSS 中,将逻辑放在 JavaScript 中,而且通常是在不同的文件中!内容在 HTML 中进行标记,而页面的逻辑则单独放在 JavaScript 中

HTML markup with purple background and a div with two child tags: p and form.
HTML markup with purple background and a div with two child tags: p and form.

HTML

Three JavaScript handlers with yellow background: onSubmit, onLogin, and onClick.
Three JavaScript handlers with yellow background: onSubmit, onLogin, and onClick.

JavaScript

但随着 Web 变得越来越具有交互性,逻辑越来越多地决定了内容。JavaScript 开始掌控 HTML!这就是为什么在 React 中,渲染逻辑和标记会放在同一个地方(组件)中。

React component with HTML and JavaScript from previous examples mixed. Function name is Sidebar which calls the function isLoggedIn, highlighted in yellow. Nested inside the function highlighted in purple is the p tag from before, and a Form tag referencing the component shown in the next diagram.
React component with HTML and JavaScript from previous examples mixed. Function name is Sidebar which calls the function isLoggedIn, highlighted in yellow. Nested inside the function highlighted in purple is the p tag from before, and a Form tag referencing the component shown in the next diagram.

Sidebar.js React 组件

React component with HTML and JavaScript from previous examples mixed. Function name is Form containing two handlers onClick and onSubmit highlighted in yellow. Following the handlers is HTML highlighted in purple. The HTML contains a form element with a nested input element, each with an onClick prop.
React component with HTML and JavaScript from previous examples mixed. Function name is Form containing two handlers onClick and onSubmit highlighted in yellow. Following the handlers is HTML highlighted in purple. The HTML contains a form element with a nested input element, each with an onClick prop.

Form.js React 组件

将按钮的渲染逻辑和标记放在一起可以确保它们在每次编辑时都能保持同步。相反,不相关的细节(例如按钮的标记和侧边栏的标记)是相互隔离的,因此可以更安全地单独更改其中任何一个。

每个 React 组件都是一个 JavaScript 函数,其中可能包含一些 React 渲染到浏览器中的标记。React 组件使用一种名为 JSX 的语法扩展来表示该标记。JSX 看起来很像 HTML,但它更严格一些,并且可以显示动态信息。理解这一点的最佳方法是将一些 HTML 标记转换为 JSX 标记。

注意

JSX 和 React 是两个不同的东西。它们经常一起使用,但你 可以 独立使用它们。JSX 是一种语法扩展,而 React 是一个 JavaScript 库。

将 HTML 转换为 JSX

假设你有一些(完全有效的)HTML

<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/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 (
    // This doesn't quite work!
    <h1>Hedy Lamarr's Todos</h1>
    <img 
      src="https://i.imgur.com/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 多了几条规则!如果你阅读上面的错误信息,它们会指导你修复标记,或者你可以按照下面的指南进行操作。

注意

大多数情况下,React 的屏幕错误信息会帮助你找到问题所在。如果你遇到问题,请仔细阅读它们!

JSX 的规则

1. 返回单个根元素

要从组件返回多个元素,请使用单个父标记将它们包装起来。

例如,你可以使用 <div>

<div>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</div>

如果你不想在标记中添加额外的 <div>,你可以改用 <></>

<>
<h1>Hedy Lamarr's Todos</h1>
<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
class="photo"
>
<ul>
...
</ul>
</>

这个空标记称为片段。片段允许你对元素进行分组,而不会在浏览器 HTML 树中留下任何痕迹。

深入探讨

为什么多个 JSX 标记需要包装起来?

JSX 看起来像 HTML,但实际上它会被转换为普通的 JavaScript 对象。如果不将两个对象封装到数组中,就不能从函数返回它们。这解释了为什么如果不将两个 JSX 标签封装到另一个标签或 Fragment 中,也不能返回它们。

2. 关闭所有标签

JSX 要求显式关闭标签:像 <img> 这样的自闭合标签必须变成 <img />,像 <li>oranges 这样的包裹标签必须写成 <li>oranges</li>

这就是海蒂·拉玛的图像和列表项关闭后的样子

<>
<img
src="https://i.imgur.com/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. 全部 大多数情况下使用驼峰式命名法!

JSX 会转换为 JavaScript,在 JSX 中编写的属性会成为 JavaScript 对象的键。在您自己的组件中,您通常希望将这些属性读入变量中。但是 JavaScript 对变量名有限制。例如,它们的名称不能包含破折号或保留字,例如 class

这就是为什么在 React 中,许多 HTML 和 SVG 属性都是用驼峰式命名法编写的。例如,使用 strokeWidth 代替 stroke-width。由于 class 是保留字,因此在 React 中,您应改用 className,它以对应的 DOM 属性命名。

<img
src="https://i.imgur.com/yXOvdOSs.jpg"
alt="Hedy Lamarr"
className="photo"
/>

您可以在DOM 组件 props 列表中找到所有这些属性。如果您弄错了,请不要担心 - React 会在浏览器控制台中打印一条消息,其中包含可能的更正。

陷阱

出于历史原因,aria-*data-* 属性的写法与 HTML 中一样,使用破折号。

专业提示:使用 JSX 转换器

在现有标记中转换所有这些属性可能会很乏味!我们建议使用转换器将您现有的 HTML 和 SVG 转换为 JSX。转换器在实践中非常有用,但仍然值得了解其工作原理,以便您能够轻松地自行编写 JSX。

这是您的最终结果

export default function TodoList() {
  return (
    <>
      <h1>Hedy Lamarr's Todos</h1>
      <img 
        src="https://i.imgur.com/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>
    </>
  );
}

回顾

现在您知道了 JSX 存在的原因以及如何在组件中使用它

  • React 组件将渲染逻辑与标记组合在一起,因为它们是相关的。
  • JSX 与 HTML 类似,但有一些区别。如果需要,您可以使用转换器
  • 错误消息通常会为您指明修复标记的正确方向。

挑战 1 1:
将一些 HTML 转换为 JSX

此 HTML 已粘贴到组件中,但它不是有效的 JSX。请修复它

export default function Bio() {
  return (
    <div class="intro">
      <h1>Welcome to my website!</h1>
    </div>
    <p class="summary">
      You can find my thoughts here.
      <br><br>
      <b>And <i>pictures</b></i> of scientists!
    </p>
  );
}

您可以选择手动完成或使用转换器!