使用 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>
</>

这个空标签被称为Fragment。 Fragments 允许你对内容进行分组,而不会在浏览器 HTML 树中留下任何痕迹。

深入探讨

为什么多个 JSX 标签需要包裹?

JSX 看起来像 HTML,但在底层它会被转换成普通的 JavaScript 对象。你不能从函数中返回两个对象而不将其包裹在一个数组中。这就是为什么你也不能返回两个 JSX 标签而不将其包裹在另一个标签或 Fragment 中。

2. 关闭所有标签

JSX 要求显式关闭标签:自闭合标签,例如 <img> 必须变成 <img />,而包装标签,例如 <li>oranges 必须写成 <li>oranges</li>

这就是 Hedy Lamarr 的图像和列表项如何关闭的

<>
<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>
  );
}

是否手动操作或使用转换器取决于你!