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

¥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

    ¥How to return different JSX depending on a condition

  • 如何有条件地包含或排除一段 JSX

    ¥How to conditionally include or exclude a piece of JSX

  • 你会在 React 代码库中遇到的常见条件语法快捷方式

    ¥Common conditional syntax shortcuts you’ll encounter in React codebases

有条件地返回 JSX

¥Conditionally returning JSX

假设你有一个 PackingList 组件渲染多个 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 逻辑与 (&&) 运算符。 Inside 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>
  );
}

如果左侧(我们的条件)是 true,则 JavaScript && 表达式 返回其右侧的值(在我们的例子中,复选标记)。但是如果条件是 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.

易犯错误

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

¥Don’t put numbers on the left side of &&.

为了测试条件,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 本身!

¥For example, a common mistake is to write code like messageCount && <p>New messages</p>. It’s easy to assume that it renders nothing when messageCount is 0, but it really renders the 0 itself!

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

¥To fix it, make the left side a boolean: 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;

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

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

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

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

¥Curly braces open the “window into JavaScript”. Embed the variable with curly braces in the returned JSX tree, nesting the previously calculated expression inside of 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 控制分支逻辑。

    ¥In React, you control branching logic with JavaScript.

  • 你可以使用 if 语句有条件地返回 JSX 表达式。

    ¥You can return a JSX expression conditionally with an if statement.

  • 你可以有条件地将一些 JSX 保存到一个变量,然后使用大括号将其包含在其他 JSX 中。

    ¥You can conditionally save some JSX to a variable and then include it inside other JSX by using the curly braces.

  • 在 JSX 中,{cond ? <A /> : <B />} 的意思是“如果 cond,则渲染 <A />,否则渲染 <B />”。

    ¥In JSX, {cond ? <A /> : <B />} means “if cond, render <A />, otherwise <B />.

  • 在 JSX 中,{cond && <A />} 的意思是“如果 cond,则渲染 <A />,否则什么也不做”。

    ¥In JSX, {cond && <A />} means “if cond, render <A />, otherwise nothing”.

  • 快捷方式很常见,但如果你喜欢普通的 if,则不必使用它们。

    ¥The shortcuts are common, but you don’t have to use them if you prefer plain if.

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

¥Show an icon for incomplete items with ? :

如果 isPacked 不是 true,则使用条件运算符 (cond ? a : b) 渲染 ❌。

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


React 中文网 - 粤ICP备13048890号