← 返回题目列表

React 错误边界是什么?能捕获哪些错误?

高频 中等 第 1 / 27 题 更新于 2026/07/29
ReactError Boundary错误处理

简化版

错误边界是 React 用来捕获子组件渲染过程错误的组件,避免整个应用白屏。它能捕获渲染、生命周期、构造函数中的错误,但不能捕获事件处理器、异步回调、服务端渲染错误。函数组件目前没有内置等价写法,通常用 class ErrorBoundary 或第三方库。

详细版

典型写法:

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    report(error, info);
  }

  render() {
    if (this.state.hasError) return <Fallback />;
    return this.props.children;
  }
}

它适合包页面、路由、复杂区块和第三方组件,错误后显示降级 UI 并上报日志。

完整版教学

一、错误边界解决局部崩溃不拖垮整站

React 渲染过程中如果某个组件抛错,可能导致整棵组件树卸载。 错误边界提供一个兜底层,让错误限制在某个区域内。 这样用户至少能看到降级 UI,而不是整个页面白屏。

没有错误边界:
  Chart 抛错 -> 页面整块崩溃
有错误边界:
  Chart 抛错 -> Chart 区域显示 fallback

例如一个仪表盘有 6 个模块,图表模块异常时,不应该让导航、用户信息、其他 5 个模块全部不可用。 错误边界的价值就是缩小故障半径。

二、错误边界由两个 class 生命周期支撑

错误边界通常是 class 组件。 static getDerivedStateFromError 用来根据错误更新状态,显示 fallback。 componentDidCatch 用来记录错误日志。

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error: Error) {
    return { hasError: true };
  }

  componentDidCatch(error: Error, info: React.ErrorInfo) {
    console.log(error, info.componentStack);
  }

  render() {
    return this.state.hasError ? <div>出错了</div> : this.props.children;
  }
}

一个负责“展示什么”,一个负责“记录什么”。 生产环境里通常会在 componentDidCatch 中上报 Sentry、日志平台或自研监控。

三、它能捕获渲染阶段错误,不能捕获所有错误

错误边界能捕获子组件渲染过程、生命周期、构造函数中的错误。 但它不能捕获事件处理器里的错误,也不能自动捕获 setTimeout、Promise 回调里的异步错误。 这是面试最常见陷阱。

function Button() {
  return (
    <button
      onClick={() => {
        throw new Error('click error');
      }}
    >
      click
    </button>
  );
}

点击事件里的错误不会被错误边界按渲染错误那样捕获。 事件错误要在事件处理器中自己 try/catch,或交给全局错误监听和日志系统。 错误边界不是 JavaScript 通用异常捕获器。

四、边界放在哪里决定故障范围

错误边界可以包整个应用,也可以包页面、路由、组件区块。 包得太大,错误影响范围大;包得太小,边界太多,维护复杂。 工程里常见做法是路由级边界加关键区块边界。

<AppShell>
  <ErrorBoundary fallback={<PageError />}>
    <RoutePage />
  </ErrorBoundary>
</AppShell>
放置位置优点风险
应用根部最后兜底一错整页 fallback
路由级页面隔离页面内部仍可能整体降级
区块级故障范围小边界数量增加

如果有 10 个业务模块,至少路由级边界能保证一个页面错误不影响整个应用外壳。

五、错误边界要配合重试和重置

只显示“出错了”还不够。 用户可能需要重试,或者切换路由后重置错误状态。 否则边界一旦进入 hasError,可能一直显示 fallback。

function Fallback({ reset }: { reset: () => void }) {
  return <button onClick={reset}>重试</button>;
}

常见策略:

错误发生
  -> 展示 fallback
  -> 上报日志
  -> 用户点击重试或路由变化
  -> 重置边界状态

很多团队会直接使用 react-error-boundary,因为它已经封装了 fallback、reset 等常用能力。

六、错误边界要和 Suspense 分清职责

Suspense 处理“还没准备好”,错误边界处理“准备失败或渲染失败”。 动态 import 加载中由 Suspense fallback 展示。 如果加载失败,错误边界负责展示错误 UI。

<ErrorBoundary fallback={<div>加载失败</div>}>
  <Suspense fallback={<div>加载中</div>}>
    <LazyPage />
  </Suspense>
</ErrorBoundary>

记忆钩子:Suspense 接住“等一等”,Error Boundary 接住“坏掉了”。

这两个边界常一起出现,但职责不能混。 回答时能讲清这点,说明你理解现代 React 的边界设计。

七、常见误区与追问

  • 误区:错误边界能捕获所有 JavaScript 错误。 它主要捕获子组件渲染阶段错误,事件处理器和异步回调不自动捕获。
  • 误区:函数组件可以直接写 componentDidCatch。 错误边界生命周期目前属于 class 组件能力,函数组件通常用封装好的边界组件。
  • 误区:根部包一个错误边界就够了。 根部兜底有必要,但关键页面和高风险区块也应有更细粒度边界。
  • 追问:错误边界能捕获自己内部的错误吗? 它不能捕获自身抛出的错误,只能捕获子组件树中的错误。
  • 追问:错误发生后如何恢复? 需要提供 reset 机制,例如点击重试、改变 key、路由变化时重置边界状态。
  • 追问:错误边界和 try/catch 有什么区别? try/catch 捕获同步命令式代码,错误边界捕获 React 渲染树中的错误。

八、加强记忆

错误边界记成“React 渲染树的保险丝”。它用 getDerivedStateFromError 展示降级 UI,用 componentDidCatch 上报错误;能捕获子组件渲染错误,但不包事件和异步。最后补边界粒度、重试恢复、和 Suspense 的区别,答案就完整了。