R38第 1 / 1 课时未开始内容版本 1.0.0 · 核验于 2026-10-26

错误边界与恢复

错误边界与恢复 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。

学习目标

读完你能实现一个可复用的错误边界组件,把可失败的局部组件隔离起来并提供恢复动作;能区分三类失败——渲染错误、事件处理错误、异步请求失败——各自的正确处理位置,不再指望一张网兜住所有问题。

问题场景

课程详情页右侧有个「评分分布」小组件。某天后端返回一条脏数据,它的渲染抛出 TypeError,结果是整页白屏——一个边缘小组件拖死了整个页面。原因:渲染阶段抛出的错误会沿着组件树一路上传,默认直到把整个根卸载,除非路上有组件声明「我来接住」。

核心解释

接住渲染错误的就是错误边界:定义了 getDerivedStateFromError(把错误转成界面)或 componentDidCatch(记录日志等副作用)的 class 组件。函数组件写不了边界,但可以用 class 包一层,内部照常使用函数组件:

class ErrorBoundary extends React.Component {
  state = { error: null };
  static getDerivedStateFromError(error) {
    return { error }; // 渲染降级界面
  }
  componentDidCatch(error, info) {
    console.error("边界捕获:", error.message); // 上报日志放这里
  }
  render() {
    if (this.state.error) return this.props.fallback(this.state.error);
    return this.props.children;
  }
}

恢复的关键是「修复数据 + 换 key 重建」:只把 error 清空,子组件内部坏掉的状态还在,可能再崩;给被包裹的子树换 key,React 会销毁重建,从源头避开坏状态。

三类失败要分清,边界不是万能网:

function handleSave() {
  try { saveSnapshot(); } catch (e) { setTip("保存失败:" + e.message); } // 事件错误:就地 catch
}
async function load() {
  try { setData(await api()); }
  catch (e) { setLoadError("加载失败,点击重试"); } // 异步失败:转成状态渲染
}
  • 渲染错误(渲染函数里抛错):边界负责;事件处理与异步回调里的错误,边界管不到;
  • 事件处理错误:不会引发白屏,在处理函数里 try/catch 即可,不交给边界;
  • 异步请求失败:Promise 的 reject 发生在边界的捕获范围之外,应在请求层 catch 后转成状态(如 error 字段)再渲染出来。

示例拆解

实验区页面里有一个「评分分布」组件,开关能注入脏数据让它在渲染期抛错:

  • 页面级边界模式:勾选脏数据,整页降级为错误提示——这就是粒度太粗的后果,恢复按钮做「修复数据 + 换 key 重建」;
  • 组件级边界模式:同样的错误,只有小组件位置显示「暂时不可用」,页面其余部分完全正常;
  • 「触发事件错误」按钮:try/catch 就地捕获,只在角落显示一条红色提示,页面无感;
  • 异步面板:模拟请求失败,错误态由面板自己的状态渲染,全程不经过错误边界;
  • 验证:三种失败逐一触发,确认影响范围与处理位置符合预期。

动手任务

打开本课实验区:

  1. 两种边界粒度各注入一次脏数据,记录降级范围的差别;执行一次「重试」,观察它先清脏数据再换 key。
  2. 给边界 fallback 加一个「上报日志」按钮,点击后把错误堆栈输出到 console。
  3. 把异步面板改成「最多自动重试 2 次,仍失败才显示失败态」,用状态计数实现。

常见错误

  • 以为边界能接住事件和异步错误:它们不发生在渲染阶段,边界根本不触发;对应位置用 try/catch 或请求层错误状态。
  • 整个页面包一个边界:任何一处崩溃整页降级;边界应贴着「可失败单元」放置。
  • 恢复只清 error 不重建:子组件内部坏状态还在,再渲染可能再崩;用 key 重建子树。
  • 在 render 里写 try/catch 期望兜住子组件错误:渲染期错误走边界机制,不走 try/catch。

检查与复盘

自查清单:

  • 能默写错误边界的两个关键 API 与各自职责(降级界面 / 记录日志)
  • 三类失败能各说出正确的处理位置
  • 边界粒度贴着可失败组件,恢复用「修复数据 + 换 key」并验证过

参考资料

动手实验
动手实验
预览
点击「运行」在隔离沙箱中预览
检查题共 1 题,提交后立即显示解析
答案由服务端判定;答错的题会自动进入复习计划。
Q1故障定位较难

bug 现场:项目用 react-error-boundary 的 <ErrorBoundary> 组件包住了表单区。点击「保存」时 handleSave 抛错(输入了非法 JSON),结果整页白屏,错误边界的 fallback 没有出现。为什么?怎么补救?

// 使用 react-error-boundary 包裹表单区:
// <ErrorBoundary fallback={<p>表单出错了</p>}>
//   <SaveForm />
// </ErrorBoundary>

// SaveForm 内部:
function handleSave() {
  const data = JSON.parse(rawInput.value); // 输入非法 JSON 时抛错
  submit(data);
}

读完这一课了?

标记完成后,工作台会安排接下来的学习。

Command Palette

Search for a command to run...