条件渲染
您的组件通常需要根据不同的条件显示不同的内容。 在 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,则不必使用它们。