React 错误边界处理

使用 Error Boundary 统一捕获 React 组件错误

问题

如何统一监听 React 组件报错?

解答

React 提供了 Error Boundary(错误边界)机制来捕获子组件树中的 JavaScript 错误。

创建错误边界组件

import React, { Component } from 'react';

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

  // 静态方法:根据错误更新 state
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  // 捕获错误信息和组件栈
  componentDidCatch(error, errorInfo) {
    // 上报错误到监控服务
    console.log('错误信息:', error);
    console.log('组件栈:', errorInfo.componentStack);
    
    // 可以发送到错误监控平台
    // reportError(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // 降级 UI
      return this.props.fallback || <h1>页面出错了</h1>;
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

使用错误边界

import ErrorBoundary from './ErrorBoundary';

function App() {
  return (
    <ErrorBoundary fallback={<div>出错了,请刷新页面</div>}>
      <Header />
      <ErrorBoundary fallback={<div>内容加载失败</div>}>
        <MainContent />
      </ErrorBoundary>
      <Footer />
    </ErrorBoundary>
  );
}

错误边界无法捕获的情况

// 1. 事件处理函数中的错误(需要 try-catch)
function Button() {
  const handleClick = () => {
    try {
      throw new Error('点击错误');
    } catch (error) {
      console.log(error);
    }
  };
  return <button onClick={handleClick}>点击</button>;
}

// 2. 异步代码(setTimeout、Promise)
useEffect(() => {
  setTimeout(() => {
    // 这里的错误不会被 ErrorBoundary 捕获
  }, 1000);
}, []);

// 3. 服务端渲染

// 4. 错误边界组件自身的错误

配合全局错误监听

// 捕获未处理的 Promise 错误
window.addEventListener('unhandledrejection', (event) => {
  console.log('未处理的 Promise 错误:', event.reason);
});

// 捕获全局 JS 错误
window.addEventListener('error', (event) => {
  console.log('全局错误:', event.error);
});

React 19+ 的新特性

// React 19 支持在 createRoot 时配置错误处理
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'), {
  onCaughtError: (error, errorInfo) => {
    // 被 ErrorBoundary 捕获的错误
    console.log('捕获的错误:', error);
  },
  onUncaughtError: (error, errorInfo) => {
    // 未被捕获的错误
    console.log('未捕获的错误:', error);
  }
});

关键点

  • Error Boundary 只能用 class 组件实现,需要 getDerivedStateFromErrorcomponentDidCatch
  • getDerivedStateFromError 用于渲染降级 UI,componentDidCatch 用于记录错误
  • 无法捕获:事件处理、异步代码、SSR、自身错误
  • 可以嵌套使用,实现不同粒度的错误处理
  • 配合 window.onerrorunhandledrejection 实现完整的错误监控