你的组件通常需要根据不同的条件显示不同的内容。在 React 中,你可以使用 JavaScript 语法有条件地渲染 JSX,比如 if 语句、&&? : 运算符。

🌐 Your components will often need to display different things depending on different conditions. In React, you can conditionally render JSX using JavaScript syntax like if statements, &&, and ? : operators.

你将学习到

  • 如何根据条件返回不同的 JSX
  • 如何有条件地包含或排除一段 JSX
  • 你会在 React 代码库中遇到的常见条件语法快捷方式

有条件地返回 JSX

🌐 Conditionally returning JSX

假设你有一个 PackingList 组件,它渲染了多个 Item,这些 Item 可以被标记为已打包或未打包:

🌐 Let’s say you have a PackingList component rendering several Items, which can be marked as packed or not:

function Item({ name, isPacked }) {
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

注意,一些 Item 组件的 isPacked 属性被设置为 true 而不是 false。如果 isPacked={true},你想在已打包的物品上添加一个勾号 (✅)。

🌐 Notice that some of the Item components have their isPacked prop set to true instead of false. You want to add a checkmark (✅) to packed items if isPacked={true}.

你可以像这样将其写成一个if/else语句

🌐 You can write this as an if/else statement like so:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

如果 isPacked 属性是 true,这段代码会返回一个不同的 JSX 树。 经过此更改,部分项目在末尾会显示一个对勾:

🌐 If the isPacked prop is true, this code returns a different JSX tree. With this change, some of the items get a checkmark at the end:

function Item({ name, isPacked }) {
  if (isPacked) {
    return <li className="item">{name}</li>;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

尝试编辑在这两种情况下返回的内容,看看结果如何变化!

🌐 Try editing what gets returned in either case, and see how the result changes!

注意你是如何使用 JavaScript 的 ifreturn 语句创建分支逻辑的。在 React 中,控制流程(例如条件)是由 JavaScript 处理的。

🌐 Notice how you’re creating branching logic with JavaScript’s if and return statements. In React, control flow (like conditions) is handled by JavaScript.

使用 null 有条件地不返回任何内容

🌐 Conditionally returning nothing with null

在某些情况下,你可能根本不想渲染任何内容。例如,假设你根本不想显示打包的项目。组件必须返回某些内容。在这种情况下,你可以返回 null

🌐 In some situations, you won’t want to render anything at all. For example, say you don’t want to show packed items at all. A component must return something. In this case, you can return null:

if (isPacked) {
return null;
}
return <li className="item">{name}</li>;

如果 isPacked 为真,该组件将不返回任何内容,即 null。否则,它将返回用于渲染的 JSX。

🌐 If isPacked is true, the component will return nothing, null. Otherwise, it will return JSX to render.

function Item({ name, isPacked }) {
  if (isPacked) {
    return null;
  }
  return <li className="item">{name}</li>;
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

在实际操作中,从一个组件返回 null 并不常见,因为这可能会让试图渲染它的开发者感到意外。更常见的做法是在父组件的 JSX 中有条件地包含或排除该组件。下面是实现的方法!

🌐 In practice, returning null from a component isn’t common because it might surprise a developer trying to render it. More often, you would conditionally include or exclude the component in the parent component’s JSX. Here’s how to do that!

有条件地包含 JSX

🌐 Conditionally including JSX

在前面的例子中,你控制了组件将返回哪个(如果有的话!)JSX 树。你可能已经注意到渲染输出中有一些重复:

🌐 In the previous example, you controlled which (if any!) JSX tree would be returned by the component. You may already have noticed some duplication in the render output:

<li className="item">{name}</li>

非常相似

🌐 is very similar to

<li className="item">{name}</li>

两个条件分支都返回 <li className="item">...</li>

🌐 Both of the conditional branches return <li className="item">...</li>:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

虽然这种重复并无害处,但它可能会让你的代码更难维护。如果你想修改 className,你就必须在代码中的两个地方进行修改!在这种情况下,你可以有条件地包含一些 JSX 来使你的代码更加 DRY.

🌐 While this duplication isn’t harmful, it could make your code harder to maintain. What if you want to change the className? You’d have to do it in two places in your code! In such a situation, you could conditionally include a little JSX to make your code more DRY.

条件(三元)运算符(? :

🌐 Conditional (ternary) operator (? :)

JavaScript 具有用于编写条件表达式的紧凑语法——条件运算符 或“三元运算符”.

🌐 JavaScript has a compact syntax for writing a conditional expression — the conditional operator or “ternary operator”.

而不是这样:

🌐 Instead of this:

if (isPacked) {
return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;

你可以这样写:

🌐 You can write this:

return (
<li className="item">
{isPacked ? name + ' ✅' : name}
</li>
);

你可以将其理解为*“如果 isPacked 为真,则渲染 (?) name + ' ✅',否则渲染 (:) name”*。

🌐 You can read it as “if isPacked is true, then (?) render name + ' ✅', otherwise (:) render name.

深入研究

这两个例子完全等价吗?

🌐 Are these two examples fully equivalent?

如果你来自面向对象编程背景,你可能会认为上面两个例子略有不同,因为其中一个可能会创建两个不同的 <li>“实例”。但是 JSX 元素并不是“实例”,因为它们不持有任何内部状态,也不是真实的 DOM 节点。它们是轻量级的描述,就像蓝图一样。因此这两个例子实际上完全等价保留和重置状态 详细说明了这是如何工作的。

🌐 If you’re coming from an object-oriented programming background, you might assume that the two examples above are subtly different because one of them may create two different “instances” of <li>. But JSX elements aren’t “instances” because they don’t hold any internal state and aren’t real DOM nodes. They’re lightweight descriptions, like blueprints. So these two examples, in fact, are completely equivalent. Preserving and Resetting State goes into detail about how this works.

现在假设你想将已完成项目的文本用另一个 HTML 标签封装起来,例如 <del> 来删除线。你甚至可以添加更多的换行和括号,这样在每种情况下更容易嵌套更多的 JSX:

🌐 Now let’s say you want to wrap the completed item’s text into another HTML tag, like <del> to strike it out. You can add even more newlines and parentheses so that it’s easier to nest more JSX in each of the cases:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {isPacked ? (
        <del>
          {name + ' ✅'}
        </del>
      ) : (
        name
      )}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

这种风格适用于简单的条件,但要适度使用。如果你的组件因为过多嵌套的条件标记而变得混乱,可以考虑提取子组件来清理。 在 React 中,标记是代码的一部分,因此你可以使用变量和函数等工具来整理复杂的表达式。

🌐 This style works well for simple conditions, but use it in moderation. If your components get messy with too much nested conditional markup, consider extracting child components to clean things up. In React, markup is a part of your code, so you can use tools like variables and functions to tidy up complex expressions.

逻辑与运算符(&&

🌐 Logical AND operator (&&)

你会遇到的另一个常见快捷方式是 JavaScript 逻辑与(&&)运算符。 在 React 组件中,当你想在条件为真时渲染一些 JSX,否则什么都不渲染时,它经常会用到。使用 &&,你可以只有在 isPackedtrue 时才有条件地渲染复选标记:

🌐 Another common shortcut you’ll encounter is the JavaScript logical AND (&&) operator. Inside React components, it often comes up when you want to render some JSX when the condition is true, or render nothing otherwise. With &&, you could conditionally render the checkmark only if isPacked is true:

return (
<li className="item">
{name} {isPacked && '✅'}
</li>
);

你可以将其理解为“如果 isPacked,则渲染勾号(&&),否则不渲染任何内容”。

🌐 You can read this as “if isPacked, then (&&) render the checkmark, otherwise, render nothing”.

下面是它的实际应用:

🌐 Here it is in action:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✅'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

一个 JavaScript && 表达式 如果左侧(我们的条件)为 true,则返回右侧的值(在我们的例子中就是勾号)。但如果条件为 false,整个表达式就变成 false。React 将 false 视为 JSX 树中的“空洞”,就像 nullundefined 一样,并且不会在其位置渲染任何内容。

🌐 A JavaScript && expression returns the value of its right side (in our case, the checkmark) if the left side (our condition) is true. But if the condition is false, the whole expression becomes false. React considers false as a “hole” in the JSX tree, just like null or undefined, and doesn’t render anything in its place.

易犯错误

不要在 && 的左侧放数字。

为了测试条件,JavaScript 会自动将左侧转换为布尔值。然而,如果左侧是 0,那么整个表达式将得到该值(0),并且 React 会高兴地渲染 0 而不是什么都不渲染。

🌐 To test the condition, JavaScript converts the left side to a boolean automatically. However, if the left side is 0, then the whole expression gets that value (0), and React will happily render 0 rather than nothing.

例如,一个常见的错误是写出像 messageCount && <p>New messages</p> 这样的代码。很容易假设当 messageCount0 时它不会渲染任何东西,但它实际上会渲染 0 本身!

要修复它,请将左侧改为布尔值:messageCount > 0 && <p>New messages</p>

有条件地将 JSX 分配给变量

🌐 Conditionally assigning JSX to a variable

当快捷方式妨碍编写简单代码时,尝试使用 if 语句和一个变量。使用 let 定义的变量可以重新赋值,所以先提供你想显示的默认内容,名称为:

🌐 When the shortcuts get in the way of writing plain code, try using an if statement and a variable. You can reassign variables defined with let, so start by providing the default content you want to display, the name:

let itemContent = name;

使用 if 语句将 JSX 表达式重新分配给 itemContent,如果 isPackedtrue

🌐 Use an if statement to reassign a JSX expression to itemContent if isPacked is true:

if (isPacked) {
itemContent = name + " ✅";
}

大括号打开“JavaScript窗口”。 在返回的 JSX 树中使用大括号嵌入变量,将之前计算的表达式嵌套在 JSX 内部:

<li className="item">
{itemContent}
</li>

这种风格是最冗长的,但它也是最灵活的。下面是它的实际应用:

🌐 This style is the most verbose, but it’s also the most flexible. Here it is in action:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✅";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

和以前一样,这不仅适用于文本,也适用于任意 JSX:

🌐 Like before, this works not only for text, but for arbitrary JSX too:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = (
      <del>
        {name + " ✅"}
      </del>
    );
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}

如果你不熟悉 JavaScript,这种多样的风格一开始可能会让人感到不知所措。然而,学习它们将帮助你阅读和编写任何 JavaScript 代码——不仅仅是 React 组件!首先选择你喜欢的一种,然后如果忘记其他风格的用法,再参考此资料。

🌐 If you’re not familiar with JavaScript, this variety of styles might seem overwhelming at first. However, learning them will help you read and write any JavaScript code — and not just React components! Pick the one you prefer for a start, and then consult this reference again if you forget how the other ones work.

回顾

  • 在 React 中,你可以使用 JavaScript 控制分支逻辑。
  • 你可以使用 if 语句有条件地返回一个 JSX 表达式。
  • 你可以有条件地将一些 JSX 保存到一个变量,然后使用大括号将其包含在其他 JSX 中。
  • 在 JSX 中,{cond ? <A /> : <B />} 的意思是 “如果 cond,渲染 <A />,否则渲染 <B />
  • 在 JSX 中,{cond && <A />} 的意思是 “如果 cond,则渲染 <A />,否则什么也不渲染”
  • 这些快捷方式很常见,但如果你更喜欢普通的 if,你不必使用它们。

挑战 1 of 3:
使用 ? : 显示未完成项目的图标

🌐 Show an icon for incomplete items with ? :

使用条件运算符(cond ? a : b)在 isPacked 不是 true 时渲染❌。

🌐 Use the conditional operator (cond ? a : b) to render a ❌ if isPacked isn’t true.

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✅'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="Space suit" 
        />
        <Item 
          isPacked={true} 
          name="Helmet with a golden leaf" 
        />
        <Item 
          isPacked={false} 
          name="Photo of Tam" 
        />
      </ul>
    </section>
  );
}