美文网首页
第十六篇 描述UI-条件渲染

第十六篇 描述UI-条件渲染

作者: 深圳都这么冷 | 来源:发表于2023-02-08 09:00 被阅读0次

条件渲染

您的组件通常需要根据不同的条件显示不同的内容。 在 React 中,您可以使用 if 语句、&& 和 ? :等 JavaScript 语法的运算符有条件地渲染 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'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},您想要向已打包的项目添加复选标记 (✔)。

您可以将其写成 if/else 语句,如下所示:

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

如果 isPacked 属性为真,这段代码返回一个不同的 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'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 的 if 和 return 语句创建分支逻辑的。 在 React 中,控制流(如条件)由 JavaScript 处理。

有条件地返回 null

在某些情况下,您根本不想渲染任何东西。 例如,假设您根本不想显示包装好的物品。 一个组件必须返回一些东西。 在这种情况下,您可以返回 null:

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

如果 isPacked 为真,组件将不返回任何内容,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'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 中有条件地包含或排除该组件。 这是如何做到的呢!

有条件地包含 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 为真,则 (?) 渲染名称 + '✔',否则 (:) 渲染名称”。

深度阅读: 这两个例子完全等价吗?

如果你有面向对象的编程背景,你可能会认为上面的两个例子有细微的不同,因为其中一个可能创建了 <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'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 中,标记是代码的一部分,因此您可以使用变量和函数等工具来整理复杂的表达式。

逻辑与运算符 (&&)

您会遇到的另一个常见快捷方式是 JavaScript 逻辑与 (&&) 运算符。 在 React 组件中,当你想在条件为真时渲染一些 JSX,或者在其他情况下什么都不渲染时,它经常会出现。 使用 &&,您可以仅在 isPacked 为真时有条件地呈现复选标记:

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

您可以将其理解为“如果 isPacked,则 (&&) 呈现复选标记,否则,不呈现任何内容”。

如果左侧(我们的条件)为真,则 JavaScript && 表达式返回其右侧的值(在我们的例子中,复选标记)。 但如果条件为假,则整个表达式变为假。 React 将 false 视为 JSX 树中的一个“洞”,就像 null 或 undefined 一样,并且不会在其位置呈现任何内容。

"陷阱

不要把数字放在 && 的左边。

为了测试条件,JavaScript 自动将左侧转换为布尔值。 然而,如果左边是 0,那么整个表达式都会得到那个值 (0),React 会愉快地呈现 0 而不是什么都没有。

例如,一个常见的错误是编写类似 messageCount && <p>New messages</p> 的代码。 很容易假设当 messageCount 为 0 时它不呈现任何内容,但它确实呈现了 0 本身!

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

有条件地将 JSX 赋值给变量

当快捷方式妨碍了编写纯代码时,请尝试使用 if 语句和变量。 您可以重新分配使用 let 定义的变量,因此首先提供您要显示的默认内容,名称:

let itemContent = name;

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

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

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

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

这种风格是最冗长的,但也是最灵活的。 以下是实战:

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:

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 组件! 选择您喜欢的开始,如果您忘记了其他的工作原理,请再次查阅此参考资料。

回顾

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

相关文章