Skip to content

react中的错误捕获

在 React 中捕获组件错误主要有两种核心方式:错误边界(Error Boundary)try/catch 捕获,分别适用于不同场景。

1. 错误边界(Error Boundary):捕获子组件渲染错误

错误边界是 React 提供的一种类组件,专门用于捕获子组件树中的 JavaScript 错误,并提供降级 UI(替代崩溃的组件),而不会导致整个应用崩溃。

核心原理:

通过类组件的两个生命周期方法捕获错误:

  • static getDerivedStateFromError(error):渲染降级 UI(更新 state)。
  • componentDidCatch(error, errorInfo):记录错误信息(如日志上报)。

使用示例:

jsx
// 定义错误边界组件
class ErrorBoundary extends React.Component {
    state = {hasError: false, error: null};

    // 错误发生后更新状态,渲染降级 UI
    static getDerivedStateFromError(error) {
        return {hasError: true, error};
    }

    // 记录错误信息(可选)
    componentDidCatch(error, errorInfo) {
        console.error("组件错误:", error, errorInfo);
        // 可在此处上报错误到日志服务
    }

    render() {
        if (this.state.hasError) {
            // 自定义降级 UI
            return this.props.fallback || <div>发生错误,请刷新页面重试</div>;
        }
        // 无错误时渲染子组件
        return this.props.children;
    }
}

// 使用错误边界包裹可能出错的组件
function App() {
    return (
        <div>
            <h1>正常内容</h1>
            {/* 用错误边界包裹可能崩溃的组件 */}
            <ErrorBoundary fallback={<div>用户列表加载失败</div>}>
                <UserList/>
            </ErrorBoundary>
        </div>
    );
}

// 可能出错的子组件
function UserList() {
    // 模拟错误:调用不存在的变量
    return <div>{undefinedVariable.map()}</div>;
}

适用场景:

  • 捕获子组件的渲染错误(如 JSX 语法错误、组件内部逻辑错误)。
  • 捕获生命周期方法中的错误
  • 捕获子组件树中任意深度的错误

局限性:

  • 不能捕获自身错误(只能捕获子组件错误)。
  • 不能捕获异步错误(如 setTimeoutfetch 回调中的错误)。
  • 不能捕获事件处理函数中的错误(如 onClick 中的错误)。

2. try/catch:捕获同步和异步错误

对于错误边界无法覆盖的场景(如异步操作、事件处理),需使用原生 try/catch 捕获错误。

适用场景:

  • 事件处理函数(如 onClickonChange):

    jsx
    function Button() {
      const handleClick = () => {
        try {
          // 可能出错的逻辑
          JSON.parse('invalid-json');
        } catch (error) {
          console.error("点击事件错误:", error);
        }
      };
    
      return <button onClick={handleClick}>点击</button>;
    }
  • 异步操作(如 setTimeoutPromiseasync/await):

    jsx
    function DataFetcher() {
      const [data, setData] = useState(null);
    
      useEffect(() => {
        // 异步请求中的错误捕获
        const fetchData = async () => {
          try {
            const res = await fetch('/invalid-api');
            const data = await res.json();
            setData(data);
          } catch (error) {
            console.error("接口请求错误:", error);
          }
        };
    
        fetchData();
      }, []);
    
      return <div>{data?.content || '加载中...'}</div>;
    }
  • 自定义 Hooks 中的逻辑错误

    jsx
    function useCustomHook() {
      try {
        // 可能出错的逻辑
        if (someCondition) {
          throw new Error("自定义 Hooks 错误");
        }
      } catch (error) {
        console.error("Hooks 错误:", error);
      }
    }

3. 全局错误捕获(补充方案)

对于未被错误边界和 try/catch 捕获的全局错误,可通过以下方式兜底:

  • 捕获 React 渲染外的错误
    jsx
    // 捕获同步代码错误
    window.addEventListener('error', (event) => {
      console.error("全局同步错误:", event.error);
    });
    
    // 捕获未处理的 Promise 错误(如 fetch 失败未 catch)
    window.addEventListener('unhandledrejection', (event) => {
      console.error("未处理的 Promise 错误:", event.reason);
      event.preventDefault(); // 阻止浏览器默认提示
    });

总结:错误捕获方案选择

错误类型推荐方案
子组件渲染错误错误边界(Error Boundary)
生命周期方法错误错误边界
事件处理函数错误try/catch
异步操作错误(Promise/setTimeout)try/catch
全局未捕获错误window.error / unhandledrejection

通过组合使用这些方案,可以全面覆盖 React 应用中的各类错误场景,提升应用的健壮性。