React 错误边界 Error Boundaries 捕获渲染时的错误

FreeGuideOnline 最新 2026-07-04

什么是 React 错误边界

错误边界是一种 React 组件,它能够捕获渲染过程生命周期方法以及构造函数中发生的 JavaScript 错误,并展示回退 UI(Fallback UI),从而避免整个应用白屏崩溃。

错误边界无法捕获以下场景的错误:

  • 事件处理函数中的错误(可以使用 try...catch
  • 异步代码(例如 setTimeoutPromise
  • 服务端渲染(SSR)期间
  • 错误边界自身抛出的错误

错误边界的工作方式类似于 JavaScript 的 catch {},但只针对组件树。


为什么需要错误边界

React 16 之前,组件内的错误会导致整个组件树被卸载,用户看到的是一个破碎的白屏。错误边界提供了一种“优雅降级”的机制,将错误隔离在局部,保证剩余部分仍可正常交互。

使用错误边界可以:

  • 防止整个页面崩溃
  • 向用户展示友好的错误提示
  • 记录错误日志,便于排查问题
  • 提供重试或恢复操作

如何创建错误边界

一个类组件只要实现 static getDerivedStateFromError()componentDidCatch()(或两者同时实现),它就成为了一个错误边界。

getDerivedStateFromError

  • 静态方法,返回一个对象用于更新 state
  • 允许您在错误发生后渲染降级 UI
  • 在“渲染”阶段调用,因此不应包含副作用
static getDerivedStateFromError(error) {
  // 更新 state 使下一次渲染显示降级 UI
  return { hasError: true };
}

componentDidCatch

  • 实例方法,用于记录错误信息
  • 接收 error(抛出的错误)和 errorInfo(包含组件调用栈的对象)
  • 在“提交”阶段调用,可以执行副作用(如日志上报)
componentDidCatch(error, errorInfo) {
  // 可以在这里将错误报告给第三方服务
  console.error(error, errorInfo);
}

完整示例

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

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

  componentDidCatch(error, errorInfo) {
    // 可添加错误日志服务
    logErrorToService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 自定义降级 UI
      return <h1>页面出了点问题请刷新重试</h1>;
    }

    return this.props.children; 
  }
}

使用错误边界

将错误边界包裹在可能出错的子组件外层即可。可以包裹顶层路由,也可以包裹粒度更小的组件,以便隔离影响范围。

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

推荐在以下位置设置错误边界:

  • 顶层路由组件:防止导航切换时的渲染错误导致整个应用崩溃。
  • 独立的微组件或第三方组件库:无法保证其内部永远不抛错。
  • 懒加载组件:与 React.lazy 结合使用时,可以同时处理加载和错误状态。

包裹路由示例

function App() {
  return (
    <ErrorBoundary fallback={<p>当前页面不可用</p>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/profile" element={<Profile />} />
      </Routes>
    </ErrorBoundary>
  );
}

嵌套使用

错误边界可以嵌套,错误会被最近的父级错误边界捕获。

<ErrorBoundary fallback={<DashboardError />}>
  <Dashboard>
    <ErrorBoundary fallback={<WidgetError />}>
      <ComplexWidget />
    </ErrorBoundary>
  </Dashboard>
</ErrorBoundary>

错误边界与功能组件

React 官方目前没有提供 Hooks 版本的错误边界。错误边界必须使用类组件来声明。

对于函数组件,您可以:

  • 使用现有的第三方库(如 react-error-boundary)获得声明式 API
  • 自行封装一个类组件错误边界,然后在函数组件树中使用

使用 react-error-boundary(推荐)

安装:

npm install react-error-boundary

使用:

import { ErrorBoundary } from 'react-error-boundary';

function FallbackComponent({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <p>发生错误{error.message}</p>
      <button onClick={resetErrorBoundary}>重试</button>
    </div>
  );
}

<ErrorBoundary
  FallbackComponent={FallbackComponent}
  onReset={() => {
    // 重置应用状态
  }}
>
  <MyComponent />
</ErrorBoundary>

错误恢复策略

一个好的降级 UI 通常包含“重试”或“重置”机制。可以通过 key 属性强制重新挂载错误边界内部的组件。

手动实现重置

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

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

  handleRetry = () => {
    this.setState({ hasError: false });
  };

  render() {
    if (this.state.hasError) {
      return (
        <div>
          <p>加载失败</p>
          <button onClick={this.handleRetry}>点击重试</button>
        </div>
      );
    }
    return this.props.children;
  }
}

另一种方式是利用 key 变化让 React 重新创建组件:

<ErrorBoundary key={someKey}>
  <MyComponent />
</ErrorBoundary>

someKey 改变时,ErrorBoundary 和其子节点都会被全新挂载。


错误边界的最佳实践

  1. 粒度适中
    不必为每个组件都套上错误边界,通常在页面、区块、微前端子应用等级别设置即可。

  2. 结合日志系统
    componentDidCatch 或第三方库的 onError 回调中上报错误信息和组件栈,以便快速定位生产问题。

  3. 提供有意义的回退 UI
    根据上下文给出不同的降级界面,不应只是一个空白页或通用错误提示。

  4. 不要忽略错误边界的自身错误
    如果错误边界自身抛出错误,该错误会冒泡到上层的错误边界。确保顶层至少有一个根错误边界。

  5. 配合 Suspense 处理异步组件
    React.lazy 加载失败时,如果包裹了错误边界,可以捕获 ChunkLoadError 等加载错误。


注意事项

  • 错误边界无法捕获事件处理器错误,请务必在事件处理内部使用 try...catch
  • componentDidCatch 中产生的错误不会再次被该边界捕获,将被传递给上层边界。
  • 开发环境下,错误边界显示的 UI 会在报错后快速消失,以便开发者看到错误堆栈;生产环境会稳定展示降级 UI。

总结

错误边界是 React 应用中保障稳定性的核心机制之一。通过合理设计错误边界层次结构,并结合降级 UI 与日志上报,您可以大幅提升应用的健壮性和用户体验。对于函数组件,推荐使用 react-error-boundary 简化开发,同时支持更灵活的重置与恢复模式。