React 渲染
1. 列表渲染
在应用中,我们经常需要渲染一个项目列表 (Rendering Lists),比如一个待办事项清单、用户列表或文章列表。直接在 JSX 中硬编码列表项是不现实的。
使用 map() 方法渲染列表
处理动态列表的标准做法是使用 JavaScript 的 Array.prototype.map() 方法。我们可以在 JSX 的花括号 {} 中,将一个数据数组转换为一个 React 元素数组。
function ShoppingList() {
const products = [
{ id: 1, title: "Cabbage" },
{ id: 2, title: "Garlic" },
{ id: 3, title: "Apple" },
];
const listItems = products.map((product) => (
// 对于列表中的每一项,我们都创建一个 <li> 元素
<li key={product.id}>{product.title}</li>
));
return <ul>{listItems}</ul>;
}
React 会自动渲染 listItems 数组中的所有 <li> 元素。
这里的
key属性之后会详细讲解。
将列表渲染抽取为组件
为了更好的代码组织和复用,我们可以将列表项的渲染逻辑抽取到一个单独的组件中。
// ListItem 组件负责渲染单个列表项
function ListItem({ title }) {
return <li>{title}</li>;
}
function ShoppingList() {
const products = [
{ id: 1, title: "Cabbage" },
{ id: 2, title: "Garlic" },
];
return (
<ul>
{products.map((product) => (
// key 应该放在 map 循环内部的最外层元素上
<ListItem key={product.id} title={product.title} />
))}
</ul>
);
}
2. 条件渲染
在 React 中,我们可以根据组件的状态或属性来决定渲染哪个部分。这被称为条件渲染 (Conditional Rendering)。
使用 if 语句 (守卫子句)
在组件的顶层逻辑中,我们可以使用 if 语句来提前返回(也称为“守卫子句”),这对于处理加载状态或空状态非常有用。
function ItemList({ items }) {
// 条件 1: 数据还未加载完成
if (!items) {
return <div>Loading...</div>;
}
// 条件 2: 数据为空
if (items.length === 0) {
return <div>No items found.</div>;
}
// 正常渲染
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
这种模式让代码的可读性非常高,因为它清晰地处理了各种边界情况。
使用三元运算符 ? :
对于简单的“二选一”场景,三元运算符是在 JSX 内部进行条件渲染的最佳方式。
function PackingList({ items }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}
{/* 如果 item 已打包,则显示 ✔,否则什么也不显示 */}
{item.isPacked ? "✔" : null}
</li>
))}
</ul>
);
}
返回 null 会告诉 React 在该位置不渲染任何东西。
使用逻辑与 && 运算符
当我们只想在某个条件为真时渲染一个元素,否则什么都不渲染时,逻辑与 && 运算符提供了一种更简洁的写法。
function Mailbox({ unreadMessages }) {
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 && (
<h2>You have {unreadMessages.length} unread messages.</h2>
)}
</div>
);
}
它的工作原理是:在 JavaScript 中,true && expression 总是返回 expression,而 false && expression 总是返回 false。React 不会渲染布尔值 false,因此达到了预期效果。
注意:
&&左侧的表达式不应该是数字。如果unreadMessages.length的值是0,0 && <SomeComponent />会返回0,React 会将数字0渲染到屏幕上,而不是什么都不渲染。因此,请确保&&左侧始终是一个布尔值,例如unreadMessages.length > 0。
推荐的实践方式
- 多个互斥的返回 ->
if语句: 当我们需要根据不同的条件返回完全不同的组件结构时(如加载、错误、空、成功),使用if守卫子句模式。 - 简单的二选一 -> 三元运算符
? :: 当我们需要在两个简单的 JSX 表达式之间切换时,这是最清晰的选择。 - “有或无”的场景 -> 逻辑与
&&: 当我们只想在某个条件满足时才渲染某个元素时,&&是最简洁的。 - 复杂的逻辑 -> 抽取变量: 如果条件逻辑变得复杂,最好在
return语句之前,用let声明一个变量,通过if/else逻辑给它赋不同的 JSX 值,最后在return中渲染这个变量。这可以避免 JSX 内部过于混乱。
function ComplexComponent({ status }) {
let content;
if (status === "loading") {
content = <div>Loading...</div>;
} else if (status === "error") {
content = <div>Error loading data.</div>;
} else {
content = <DataTable />;
}
return (
<div>
<h1>Dashboard</h1>
{content}
</div>
);
}