使用 React 条件渲染处理现实世界中的 UI 状态
学习如何运用实用的条件渲染模式,在 React 中构建身份验证、角色管理、权限控制以及加载状态、错误提示和空状态等 UI。
在上一篇文章中,您已经了解了条件渲染的基础知识——通过简单的条件来告诉 React 应该显示哪个组件、另一个组件,还是什么都不显示。
然而,在实际应用中情况很少如此简单:
isLoggedIn ? <Dashboard /> : <Login />
以一个真实的控制面板为例。用户可能处于以下任意一种状态:
- 已登出
- 正在登录中
- 已登录
- 管理员身份
- 普通用户
- 缺少必要权限
- 正在等待数据返回
- 遇到 API 错误
- 正在查看空结果集
每种情况都需要不同的用户界面。正是在这里,条件渲染不再只是一个小技巧,而变成了构建应用程序的真正工具。
让我们看看这在专业级的 React 代码中是如何实现的。
1. 基于身份验证的渲染
典型的应用场景就是身份验证。想象一个拥有两种可能界面的应用程序:
Not Logged In
↓
Login Page
Logged In
↓
Dashboard
React可以轻松地在它们之间切换:
function App() {
const isLoggedIn = true;
return (
<>
{isLoggedIn ? <Dashboard /> : <Login />}
</>
);
}
不过,实际应用通常还需要第三种状态:加载中,因为应用程序可能需要一些时间来确认用户的令牌是否有效。此时的流程如下:
Checking Authentication
↓
Loading
↓
Authenticated?
↙ ↘
YES NO
↓ ↓
Dashboard Login
在代码中,这可能表现为:
function App() {
const isLoading = false;
const isLoggedIn = true;
if (isLoading) {
return <LoadingSpinner />;
}
return isLoggedIn
? <Dashboard />
: <Login />;
}
你会在无数实际运行的React应用中看到这种模式反复出现。
2. 基于角色的渲染
身份验证能告诉你谁已登录,而授权则能告诉你该用户被允许执行哪些操作。
以员工管理工具为例,管理员可能会看到:
View Employees
Add Employee
Edit Employee
Delete Employee
而普通用户只能看到:
View Employees
可以根据用户的角色有条件地显示相应操作:
function EmployeeCard({ userRole }) {
return (
<div>
<h2>Employee Details</h2>
<button>View</button>
{userRole === "admin" && (
<>
<button>Edit</button>
<button>Delete</button>
</>
)}
</div>
);
}
通过这种设置,仅管理员才能看到的控件只会显示给管理员。
重要的安全提示
条件渲染可以控制用户界面中显示的内容,但隐藏元素并不能替代真正的安全措施。例如:
{isAdmin && <DeleteButton />}
这样普通用户就看不到该按钮,但服务器仍需独立确认请求确实来自有权限删除数据的人。可以这样理解这种分工:
Frontend
↓
Controls what users SEE
Backend
↓
Controls what users CAN DO
切勿将客户端条件渲染作为授权机制。
3. 基于权限的用户界面
规模较大的应用程序往往需要比简单角色更细粒度的权限控制:
Admin
User
相反,你可以定义具体的权限,例如:
CAN_VIEW_USERS
CAN_EDIT_USERS
CAN_DELETE_USERS
CAN_EXPORT_REPORT
这样,组件就可以根据现有的权限分别渲染每个操作:
function UserActions({ permissions }) {
return (
<>
{permissions.includes("CAN_EDIT_USERS") && (
<button>Edit</button>
)}
{permissions.includes("CAN_DELETE_USERS") && (
<button>Delete</button>
)}
</>
);
}
这种方法能让您更精确地控制每个用户能够执行哪些操作。
4. 加载状态
假设控制面板发起了一个需要两秒才能响应的API调用,在这段时间内屏幕上应该显示什么?当然不是空白页面——而应该是加载指示器:
if (loading) {
return <p>Loading products...</p>;
}
整体流程如下:
API Request
↓
Loading = true
↓
Show Loader
↓
API Response
↓
Loading = false
↓
Show Content
即使网络速度较慢,加载指示器也能让应用程序显得响应迅速。
5. 骨架加载器
与其显示纯文本消息,不如:
Loading...
许多现代界面会显示与即将加载的内容形状相似的占位符——即骨架加载器。例如:
┌──────────────────────┐
│ █████████████ │
│ ███████ │
│ █████████████████ │
└──────────────────────┘
当真实数据返回后,它会替换占位符:
┌──────────────────────┐
│ MacBook Air │
│ ₹99,999 │
│ ⭐⭐⭐⭐⭐ │
└──────────────────────┘
底层的 React 逻辑依然保持简单:
return loading
? <ProductSkeleton />
: <ProductCard />;
这里唯一的真正区别在于它为用户体验带来的优化。
6. 错误状态
API 调用并不总是一帆风顺。
连接可能会中断。
服务器可能会崩溃。
请求也可能会出现超时情况。
与其让应用崩溃或卡住,不如渲染错误状态。
if (error) {
return (
<div>
<h2>Something went wrong.</h2>
<button>Try Again</button>
</div>
);
}
优雅地处理故障是高质量用户界面的重要特征。
7. 加载中 + 错误 + 成功
在实际使用中,这三种状态几乎总是同时出现。
function ProductList({
loading,
error,
products
}) {
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Something went wrong.</p>;
}
return <Products products={products} />;
}
你可以这样理解其流程:
Request
│
├── Loading → Loader
│
├── Failed → Error
│
└── Success → Data
在后续学习 API 调用和 useEffect 时,你会反复看到这种相同的模式。
8. 空状态
请求成功并不代表就有实际数据可以显示。
假设用户搜索了类似的内容:
"React Quantum Pizza Developer"
API 调用本身顺利完成,没有出现任何错误。
但返回的结果可能如下所示:
products.length === 0
不要让屏幕保持空白,而应给用户展示有意义的内容。
if (products.length === 0) {
return (
<div>
<h2>No Products Found</h2>
<p>Try changing your search.</p>
</div>
);
}
空状态对打造流畅的用户体验至关重要。
加载中、空状态与错误状态
新入门的 React 开发者常常混淆这三种状态,但实际上它们代表完全不同的情况。
LOADING
Data hasn't arrived yet.
EMPTY
Data arrived, but nothing exists.
ERROR
Something failed.
一个完善的程序会分别处理这三种状态。
9. 多重条件
有时,渲染结果取决于多个条件共同作用的结果。
请看以下流程:
Is User Logged In?
↓
Is Subscription Active?
↓
Is User Admin?
↓
Show Admin Dashboard
人们很容易想把所有这些内容都塞进一个巨大的嵌套三元运算式中:
condition1
? condition2
? condition3
? <A />
: <B />
: <C />
: <D />
这样的代码可以正常编译。
但阅读起来却如同噩梦一般。
更好的方法是把每个条件单独清晰地呈现出来。
if (!isLoggedIn) {
return <Login />;
}
if (!hasSubscription) {
return <UpgradePlan />;
}
if (isAdmin) {
return <AdminDashboard />;
}
return <UserDashboard />;
这种版本要容易理解得多。
10. 保护性语句
你刚刚看到的这种模式有一个名称:保护性语句,也被称为提前返回。
不必在条件中再嵌套条件:
if
└── if
└── if
└── UI
应提前处理边缘情况并立即返回。
if (loading) return <Loader />;
if (error) return <ErrorPage />;
if (!user) return <Login />;
return <Dashboard />;
这样代码结构清晰。
易于阅读。
而且调试起来也方便得多。
像 React 开发者一样思考
在编写组件之前,先问自己以下几个问题会有所帮助:
“这个界面可能处于哪些状态?”
对于通过 API 调用驱动的页面,状态列表可能如下所示:
Loading
Error
Empty
Success
在认证流程中,状态列表可能为:
Logged Out
Checking Authentication
Logged In
Unauthorized
在开始编码之前先规划好这些状态,能让后续开发的组件更易于理解。
初学者常见错误
过度使用嵌套条件语句
不要为了节省几行代码而牺牲可读性。
忽略空状态
API 返回空数组并不等同于错误——应将其视为独立的情况处理。
混淆界面隐藏与真正安全措施
仅仅通过隐藏某些内容:
<DeleteButton />
无法阻止他人直接访问你的 API 接口。
真正的授权机制必须存在于后端。
让 && 渲染错误的内容
需注意如下代码:
{items.length && <ProductList />}
如果 items.length 的值为 0,React 可能会渲染出:
0
直接显示在页面上。
更安全的写法是:
{items.length > 0 && <ProductList />}
这样条件表达式就会返回真正的布尔值。
最佳实践
在条件渲染时,可读性应始终放在首位。
建议采用如下模式:
if (loading) return <Loader />;
而非在深度嵌套的 JSX 中堆砌大量条件。
对于经常需要渲染的状态,应将其提取为独立的可复用组件:
<Loader />
<ErrorMessage />
<EmptyState />
随着组件变得愈发复杂,应将业务逻辑与实际显示的内容分开。
不要只考虑正常情况——要为界面可能出现的所有状态做好规划。
小型项目:智能控制面板
作为练习,试着构建一个能够处理以下情况的控制面板:
User Not Logged In
↓
Login ScreenUser
Logged In
↓
Loading Dashboard
↓
┌──────┴──────┐
Error Success
↓ ↓
Error UI Data Exists?
↙ ↘
YES NO
↓ ↓
Dashboard Empty State
然后在之上添加基于角色的功能:
Admin
↓
Edit + Delete
User
↓
View Only
这样的项目会同时运用多个概念:
- 属性
- 状态
- 事件
- 条件渲染
这正是当你开始构建实际应用时,React的各个组件开始协同工作的方式。
面试问题
什么是条件渲染?
它是指根据应用程序的当前状态或条件来显示不同用户界面的做法。
&&与三元运算符有什么区别?
当只需在条件为真时显示内容且其他情况下不显示任何东西时,使用 &&。若需要在条件为真和为假时分别显示不同内容,则应使用三元运算符。
什么算作空状态?
指请求成功但没有任何数据可显示时所呈现的界面。
前端基于角色的渲染足以保障安全吗?
不够。这只是界面上的便利功能——实际的授权检查仍需在后台进行。
提前返回的好处是什么?
它能减少嵌套结构,从而使条件组件更易于阅读和维护。
核心要点
至此,您已经掌握了React中的条件渲染的全部内容。
你已经看到实际应用是如何处理登录状态与未登录状态的界面展示、按角色限制屏幕访问、通过细粒度的权限控制功能启用/禁用、在数据加载时显示加载指示器、使用骨架占位符代替纯文本、在请求失败时展示错误信息、在结果集为空时向用户发送提示、将多个条件整合为连贯的流程、用保护语句简化嵌套检查,以及运用那些能让实际代码库中的逻辑更易于维护的通用做法。
条件渲染能够让你的应用根据当前所处的情况呈现最合适的体验。
但仍然存在一个挑战。
假设某个 API 返回:
1,000 Products
你真的会逐一写出:
<Product />
<Product />
<Product />
...
一千次吗?
显然不会。
React 有更出色的方式来处理这个问题。
在第9A部分中,你将学习如何使用 map() 渲染列表,并了解单个组件如何直接从数据中生成数百甚至数千个 UI 元素。
紧接着,你将面对 React 最经典的面试问题之一:
为什么 React 需要
key?
我们在第9A部分——React 中的列表渲染与键值中见。
相关阅读
- React 19.2详解:Activity、useEffectEvent与静态渲染 — 了解 React 19.2的新 Activity 组件、useEffectEvent 钩子以及部分静态渲染功能如何解决现代 UI 中的隐藏性能问题。