条件渲染与状态分支
条件渲染与状态分支 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
真实的数据视图永远不止「成功」一种样子:加载中、加载失败、结果为空都要有界面。这一课帮你把四种分支补完整,并学会用单一状态字段取代互相打架的布尔值。读完你能独立为一个请求视图设计完整的状态分支。
问题场景
课程列表页第一版用了两个布尔值:
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
function load() {
setLoading(true);
fetchCourses().then(
(list) => { setLoading(false); },
() => { setLoading(false); setError(true); }
);
}
测试时「重试按钮点了没反应」:重试时设了 loading 但忘了把 error 改回去,于是 error 和 loading 同时为 true——页面上「加载中」和「失败重试」两块同时出现。两个布尔值能组合出四种状态,其中至少一半是业务上不存在或互相矛盾的。
核心解释
分支问题本质是状态空间设计问题。 先把业务上合法的状态数一数:请求视图只有四种——loading(请求中)、error(失败)、empty(成功但没数据)、success(成功有数据)。任何时刻只能处于其中一种,这是一个互斥的集合,正适合用一个字符串字段表达:
const [status, setStatus] = useState("loading");
function load() {
setStatus("loading");
fetchCourses().then(
(list) => setStatus(list.length > 0 ? "success" : "empty"),
() => setStatus("error")
);
}
四个值互斥,不可能再出现「同时加载和失败」。渲染分支按状态展开,用提前 return 让每个分支独立成块:
function CourseList({ status, courses, onRetry }) {
if (status === "loading") return <p>加载中…</p>;
if (status === "error") return <button onClick={onRetry}>失败,点我重试</button>;
if (status === "empty") return <p>还没有课程</p>;
return <ul>{courses.map((c) => <li key={c.id}>{c.title}</li>)}</ul>;
}
什么时候仍用布尔值?当状态确实只有两态且互不交叉时,比如「弹窗开/关」,单个布尔完全够用。判断标准还是那个:数一数组合后的状态是否都合法,非法组合存在就换成互斥字段。
示例拆解
实验区是同一个课程列表的两种实现,关键点如下:
- 修复版:单个
status字段(loading / error / empty / success),三个按钮分别触发「正常请求(500ms)」「模拟失败」「模拟空结果」;每种状态各有专属界面,重试按钮总能把状态拉回 loading; - Bug 版:
loading和error两个布尔各自为政;点「模拟失败」再点「正常请求」,请求期间 error 仍是 true,页面上失败和加载同时出现; - 每个分支都处理了边界:empty 不是报错,success 才渲染列表;
- 切换状态按钮的代码能直接看出「每次进入新状态前,旧状态被显式覆盖」。
验证方式:在 Bug 版复现矛盾界面,再切到修复版做同样的操作序列,矛盾消失。
动手任务
打开本课实验区,完成三个小改动:
- 给修复版加第五种状态
offline(按钮「模拟断网」),确认加状态只需要改两处:状态赋值和渲染分支。 - 给错误分支加上失败原因文案(用
errorMsgstate 保存)。 - 在 Bug 版复现至少一种非法状态组合,说出它对应哪两个布尔值。
常见错误
- 多个布尔描述同一件事:
loading/error/done并存,组合出矛盾界面;改用一个互斥的 status 字段。 - 切换状态时漏改旧状态:重试时只设
setLoading(true)忘了setError(false);互斥字段天然没这个问题。 - empty 当 error 处理:空列表显示「出错了」误导用户;空结果属于成功分支,给专属的空状态界面。
- 分支漏网:status 有五个值但只写了四个分支,未知值时页面空白;结尾留一个兜底分支(哪怕只是 return null 加注释)。
检查与复盘
完成下方检查题确认理解。自查清单:
- 拿到一个视图先数状态:把所有合法状态列全,确认互斥
- 能说出「单布尔够用」和「必须互斥字段」的分界线
- 写完分支后逐个状态点一遍,没有空白页和矛盾界面
参考资料
- React 官方文档:条件渲染 —— 三元、&&、提前 return 的官方写法
- React 官方文档:渲染列表 —— 列表分支与空状态的组织
读完这一课了?
标记完成后,工作台会安排接下来的学习。