条件渲染

通常你的组件会需要根据不同的情况显示不同的内容。在 React 中,你可以通过使用 JavaScript 的 if 语句、&&? : 运算符来选择性地渲染 JSX。

你将会学习到

  • 如何根据不同条件返回不同的 JSX
  • 如何根据不同条件包含或者去掉部分 JSX
  • 一些你会在 React 代码库里遇到的常用的条件语法快捷表达式

条件返回 JSX

假设有一个 PackingList 组件,里面渲染多个 Item 组件,每个物品可标记为打包与否:

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

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride 的行李清单</h1>
      <ul>
        <Item
          isPacked={true}
          name="宇航服"
        />
        <Item
          isPacked={true}
          name="带金箔的头盔"
        />
        <Item
          isPacked={false}
          name="Tam 的照片"
        />
      </ul>
    </section>
  );
}

需要注意的是,有些 Item 组件的 isPacked 属性是被设为 true 而不是 false。你可以在那些满足 isPacked={true} 条件的物品旁加上一个勾选符号(✅)。

你可以用 if/else 语句 去判断:

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

如果 isPacked 属性是 true,这段代码会返回一个不一样的 JSX。通过这样的改动,一些物品的名字后面会出现一个勾选符号:

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 的行李清单</h1>
      <ul>
        <Item
          isPacked={true}
          name="宇航服"
        />
        <Item
          isPacked={true}
          name="带金箔的头盔"
        />
        <Item
          isPacked={false}
          name="Tam 的照片"
        />
      </ul>
    </section>
  );
}

动手尝试一下,看看各种情况会出现什么不同的结果!

留意这里你是怎么使用 JavaScript 的 ifreturn 语句来写分支逻辑。在 React 中,是由 JavaScript 来处理控制流的(比如条件)。

选择性地返回 null

在一些情况下,你不想有任何东西进行渲染。比如,你不想显示已经打包好的物品。但一个组件必须返回一些东西。这种情况下,你可以直接返回 null

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

如果组件的 isPacked 属性为 true,那么它将只返回 null。否则,它将返回相应的 JSX 用来渲染。

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

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride 的行李清单</h1>
      <ul>
        <Item
          isPacked={true}
          name="宇航服"
        />
        <Item
          isPacked={true}
          name="带金箔的头盔"
        />
        <Item
          isPacked={false}
          name="Tam 的照片"
        />
      </ul>
    </section>
  );
}

实际上,在组件里返回 null 并不常见,因为这样会让想使用它的开发者感觉奇怪。通常情况下,你可以在父组件里选择是否要渲染该组件。让我们接着往下看吧!

选择性地包含 JSX

在之前的例子里,你在组件内部控制哪些 JSX 树(如果有的话!)会返回。你可能已经发现了在渲染输出里会有一些重复的内容:

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

和下面的写法很像:

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

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

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

虽然这些重复的内容没什么害处,但这样可能会导致你的代码更难维护。比如你想更改 className?你就需要修改两个地方!针对这种情况,你可以通过选择性地包含一小段 JSX 来让你的代码更加 DRY

三目运算符(? :

JavaScript 有一种紧凑型语法来实现条件判断表达式——条件运算符 又称“三目运算符”。

除了这样:

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

你还可以这样实现:

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

你可以认为,“如果 isPacked 为 true 时,则(?)渲染 name + ' ✅',否则(:)渲染 name。”

深入探讨

两个例子完全一样吗?

如果你之前是习惯面向对象开发的,你可能会认为上面的两个例子略有不同,因为其中一个可能会创建两个不同的 <li> “实例”。但 JSX 元素不是“实例”,因为它们没有内部状态也不是真实的 DOM 节点。它们只是一些简单的描述,就像图纸一样。所以上面这两个例子事实上是完全相同的。在 状态的保持和重置 里会深入探讨其原因。

现在,假如你想将对应物品的文本放到另一个 HTML 标签里,比如用 <del> 来显示删除线。你可以添加更多的换行和括号,以便在各种情况下更好地去嵌套 JSX:

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

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride 的行李清单</h1>
      <ul>
        <Item
          isPacked={true}
          name="宇航服"
        />
        <Item
          isPacked={true}
          name="带金箔的头盔"
        />
        <Item
          isPacked={false}
          name="Tam 的照片"
        />
      </ul>
    </section>
  );
}

对于简单的条件判断,这样的风格可以很好地实现,但需要适量使用。如果你的组件里有很多的嵌套式条件表达式,则需要考虑通过提取为子组件来简化这些嵌套表达式。在 React 里,标签也是你代码中的一部分,所以你可以使用变量和函数来整理一些复杂的表达式。

与运算符(&&