错误边界处理

引言

在 React 应用中,一个组件的错误不应导致整个应用崩溃。错误边界(Error Boundaries)是 React 提供的错误隔离机制,它能捕获子组件树中的 JavaScript 错误,并显示降级 UI 而非让整个应用白屏。


什么是错误边界?

错误边界是类组件 ,通过实现 getDerivedStateFromError()componentDidCatch() 生命周期方法来捕获子组件的错误。

javascript 复制代码
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    // 渲染降级 UI
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // 记录错误日志
    console.error('捕获错误:', error, errorInfo);
    this.setState({ error });
  }

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

核心 API 对比

方法 调用时机 用途 能否访问组件实例
getDerivedStateFromError 渲染阶段 更新 state 显示降级 UI ❌ 静态方法
componentDidCatch 提交阶段 记录错误日志、上报 ✅ 可访问实例

实战:完整的错误边界组件

javascript 复制代码
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { 
      hasError: false, 
      error: null,
      errorInfo: null
    };
  }

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

  componentDidCatch(error, errorInfo) {
    this.setState({ error, errorInfo });
    
    // 上报到错误监控平台
    logErrorToService(error, errorInfo);
  }

  handleRetry = () => {
    this.setState({ hasError: false, error: null, errorInfo: null });
  };

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-boundary">
          <h2>😕 出错了</h2>
          <p>组件渲染失败,请尝试刷新</p>
          <button onClick={this.handleRetry}>重试</button>
          {process.env.NODE_ENV === 'development' && (
            <details>
              <summary>错误详情</summary>
              <pre>{this.state.error?.toString()}</pre>
            </details>
          )}
        </div>
      );
    }
    return this.props.children;
  }
}

错误上报策略

javascript 复制代码
// 错误上报服务
async function logErrorToService(error, errorInfo) {
  const errorData = {
    message: error.message,
    stack: error.stack,
    componentStack: errorInfo.componentStack,
    url: window.location.href,
    userAgent: navigator.userAgent,
    timestamp: Date.now()
  };

  // 使用 sendBeacon 确保上报成功
  navigator.sendBeacon('/api/log-error', JSON.stringify(errorData));
  
  // 或发送到第三方监控平台
  // Sentry.captureException(error, { contexts: { react: errorInfo } });
}

使用场景

javascript 复制代码
// ✅ 包裹可能出错的子组件
<ErrorBoundary>
  <UserProfile userId={123} />
</ErrorBoundary>

// ✅ 多个独立边界,隔离错误
<ErrorBoundary fallback={<ChatFallback />}>
  <ChatWidget />
</ErrorBoundary>

<ErrorBoundary fallback={<FeedFallback />}>
  <NewsFeed />
</ErrorBoundary>

// ❌ 不要包裹整个应用(失去隔离意义)
<ErrorBoundary>
  <App />
</ErrorBoundary>

注意事项

能捕获 不能捕获
子组件渲染错误 事件处理器中的错误
生命周期错误 异步代码(setTimeout、requestAnimationFrame)
构造函数错误 SSR 服务端错误
边界组件自身的错误

总结

  1. 错误边界必须是类组件(Hooks 方案需用第三方库如 react-error-boundary)
  2. 精细化包裹:在可能出错的组件周围单独设置边界
  3. 优雅降级:提供友好的错误提示和重试机制
  4. 错误上报:记录错误信息用于后续分析修复
  5. 开发环境:显示详细错误信息便于调试
相关推荐
程序员小寒2 小时前
JavaScript设计模式(七):迭代器模式实现与应用
前端·javascript·设计模式·迭代器模式
晓13132 小时前
React篇——第七章 React 19 编译器深度解析
前端·javascript·react.js
Jacob00002 小时前
【Vue | initial】 创建初始化项目
前端
im_AMBER2 小时前
手撕代码之事件委托
前端·javascript·面试
用户8113581881202 小时前
React全家桶笔记(三):React进阶 — 事件处理、表单与生命周期
前端
用户8113581881202 小时前
React全家桶笔记(二):React组件核心 — State、Props、Refs
前端
Jenlybein2 小时前
一文了解 pnpm,并快速上手操作!
前端·javascript·npm
大萝卜呼呼2 小时前
Next.js第二课 - 项目结构详解 - 优栈
前端·next.js
skywalkzf2 小时前
全志 V853 开发:lunch 不显示项目列表问题排查与解决
前端·chrome