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