4、React条件渲染:if/else、三元运算符、逻辑与运算符、条件渲染最佳实践
条件渲染,说白了就是「根据不同的状态,显示不同的UI」。
我刚开始写React时,觉得这玩意儿太简单了——不就是个if判断吗?结果项目一复杂,各种条件嵌套、代码冗余、可读性暴跌……嗯,这里面的门道其实不少。
今天咱们就把React条件渲染的几种方式掰开揉碎,看看什么时候用if/else,什么时候用三元,什么时候用&&,以及我踩过的那些坑。
4.1 最基本的if/else
在JSX里,你不能直接写if语句。因为JSX本质上是个语法糖,最终会被编译成React.createElement调用。但我们可以把if/else放在JSX外面。
function UserGreeting({ user }) {
if (user) {
return <h1>欢迎回来,{user.name}!</h1>;
} else {
return <h1>请先登录</h1>;
}
}
这种方式最直观,逻辑清晰。我在项目中处理复杂的多分支条件时,首选就是if/else。
4.2 三元运算符:简洁但别滥用
三元运算符是JSX里最常用的条件渲染方式。它本质上就是个表达式,可以直接写在JSX的花括号里。
function StatusBadge({ isActive }) {
return (
<span className={isActive ? 'badge-success' : 'badge-danger'}>
{isActive ? '已激活' : '未激活'}
</span>
);
}
三元运算符适合「二选一」的场景。但如果你嵌套使用,代码就会变得很难读。
// ❌ 不推荐:三层嵌套,可读性极差
return (
<div>
{isAdmin ? (isSuper ? '超级管理员' : '普通管理员') : (isVip ? 'VIP用户' : '普通用户')}
</div>
);
// ✅ 推荐:提取成函数或变量
const getRoleLabel = () => {
if (isAdmin) return isSuper ? '超级管理员' : '普通管理员';
return isVip ? 'VIP用户' : '普通用户';
};
return <div>{getRoleLabel()}</div>;
4.3 逻辑与运算符:简洁的「有则显示」
逻辑与(&&)是React条件渲染里最优雅的方式之一。它特别适合「满足条件就显示,不满足就什么都不显示」的场景。
function NotificationBadge({ count }) {
return (
<div>
消息
{count > 0 && <span className="badge">{count}</span>}
</div>
);
}
这里有个细节要注意:count > 0 && ... 当count为0时,表达式结果是0,React会渲染出「0」。嗯,这是个经典坑。
// ❌ 坑:当list.length为0时,会渲染出0
{list.length && <List data={list} />}
// ✅ 正确写法
{list.length > 0 && <List data={list} />}
// 或者
{!!list.length && <List data={list} />}
4.4 条件渲染的几种特殊场景
4.4.1 使用变量存储JSX
当条件逻辑比较复杂时,我习惯先把JSX存到变量里,再统一渲染。
function Dashboard({ role }) {
let dashboardContent;
if (role === 'admin') {
dashboardContent = <AdminPanel />;
} else if (role === 'editor') {
dashboardContent = <EditorPanel />;
} else {
dashboardContent = <UserPanel />;
}
return (
<div className="dashboard">
<Header />
{dashboardContent}
<Footer />
</div>
);
}
这种方式的好处是:JSX结构一目了然,条件逻辑被隔离在变量赋值阶段。
4.4.2 立即执行函数(IIFE)
有时候你不想把逻辑抽到外面,又需要在JSX里写复杂条件。这时候可以用IIFE。
function ComplexComponent({ status }) {
return (
<div>
{(() => {
switch (status) {
case 'loading':
return <Spinner />;
case 'error':
return <ErrorMsg />;
case 'empty':
return <EmptyState />;
default:
return <DataList />;
}
})()}
</div>
);
}
说实话,IIFE在团队里争议挺大的。我个人建议:除非是临时性的小逻辑,否则还是抽成单独的函数或组件更合适。
4.5 条件渲染的最佳实践
写了几年React,我总结了几条条件渲染的原则,分享给你:
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 二选一,且JSX简单 | 三元运算符 | 简洁直观,一行搞定 |
| 多分支(3个以上) | if/else 或 switch | 逻辑清晰,易于维护 |
| 有则显示,无则隐藏 | 逻辑与 && | 最优雅的写法 |
| 条件复杂,JSX结构大 | 提取为子组件 | 职责单一,可复用 |
| 条件决定整个组件内容 | 提前return | 减少嵌套,提前退出 |
4.6 一个完整的实战例子
最后,咱们看一个综合的例子。假设我们要做一个用户列表页面,有加载中、空数据、错误、正常显示四种状态。
function UserListPage() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchUsers()
.then(data => setUsers(data))
.catch(err => setError(err.message))
.finally(() => setLoading(false));
}, []);
// 加载中
if (loading) {
return <LoadingSkeleton />;
}
// 错误状态
if (error) {
return <ErrorState message={error} onRetry={fetchUsers} />;
}
// 空数据
if (users.length === 0) {
return <EmptyState />;
}
// 正常渲染
return (
<div>
<h2>用户列表(共{users.length}人)</h2>
<UserList users={users} />
</div>
);
}
你看,这里用了提前return的方式,每个状态都独立处理。代码从上往下读,逻辑非常清晰。这就是我推荐的做法。
好了,条件渲染就聊到这儿。说白了就是:选对工具,保持简洁,让别人能看懂。下一章咱们聊聊列表渲染和key的重要性,那个坑更多……