react错误边界 ErrorBoundary

React 错误边界(Error Boundary)详解

ErrorBoundary(错误边界)是 React 提供的一种错误捕获机制,用于捕获其子组件树中的 JavaScript 运行时错误,并显示降级 UI,而不是让整个应用崩溃。


1. ErrorBoundary 能解决什么问题?

假设有个组件:

复制代码
function UserInfo() {
  throw new Error('获取用户信息失败');

  return <div>用户信息</div>;
}

如果没有 ErrorBoundary:

复制代码
<App>
  <UserInfo />
</App>

页面会直接白屏:

复制代码
Error: 获取用户信息失败

有 ErrorBoundary:

复制代码
<ErrorBoundary>
  <UserInfo />
</ErrorBoundary>

页面显示:

复制代码
系统异常,请稍后重试

而不会导致整个 React 应用崩溃。


2. ErrorBoundary 能捕获哪些错误?

✅ 能捕获:

  • 生命周期方法错误

  • render 渲染错误

  • constructor 错误

  • 子组件错误

例如:

复制代码
class Demo extends React.Component {
  render() {
    throw new Error('render error');
  }
}

3. ErrorBoundary 不能捕获哪些错误?

❌ 事件函数错误

复制代码
<button
  onClick={() => {
    throw new Error('点击异常');
  }}
>
  点击
</button>

不会进入 ErrorBoundary。

需要自己 try-catch:

复制代码
const handleClick = () => {
  try {
    throw new Error('点击异常');
  } catch (err) {
    console.log(err);
  }
};

❌ 异步代码错误

复制代码
useEffect(() => {
  setTimeout(() => {
    throw new Error('异步错误');
  }, 1000);
}, []);

不会被捕获。

应该:

复制代码
useEffect(() => {
  setTimeout(() => {
    try {
      throw new Error('异步错误');
    } catch (err) {
      console.log(err);
    }
  }, 1000);
}, []);

❌ Promise 错误

复制代码
fetch('/api')
  .then(res => res.json())
  .catch(err => {
    console.log(err);
  });

需要手动 .catch()


4. ErrorBoundary 实现原理

React 提供两个生命周期:

static getDerivedStateFromError

发生错误时更新状态。

复制代码
static getDerivedStateFromError(error) {
  return {
    hasError: true
  };
}

componentDidCatch

记录错误日志。

复制代码
componentDidCatch(error, errorInfo) {
  console.log(error);
  console.log(errorInfo);
}

5. 完整实现

复制代码
import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      hasError: false
    };
  }

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

  componentDidCatch(error, errorInfo) {
    console.error('错误信息:', error);
    console.error('组件堆栈:', errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <h1>页面发生异常</h1>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

使用:

复制代码
<ErrorBoundary>
  <UserInfo />
</ErrorBoundary>

6. React 18 + TypeScript 写法

复制代码
import React, { Component, ReactNode } from 'react';

interface Props {
  children: ReactNode;
}

interface State {
  hasError: boolean;
}

class ErrorBoundary extends Component<Props, State> {
  constructor(props: Props) {
    super(props);

    this.state = {
      hasError: false
    };
  }

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

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

  render() {
    if (this.state.hasError) {
      return <div>页面异常</div>;
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

7. 函数组件如何实现?

React 官方目前没有 Hook 版 ErrorBoundary。

函数组件通常借助:

安装:

复制代码
npm install react-error-boundary

使用:

复制代码
import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error }) {
  return (
    <div>
      <p>页面异常</p>
      <pre>{error.message}</pre>
    </div>
  );
}

function App() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <UserInfo />
    </ErrorBoundary>
  );
}

8. 项目中的最佳实践

全局错误边界

复制代码
ReactDOM.createRoot(document.getElementById('root')).render(
  <ErrorBoundary>
    <App />
  </ErrorBoundary>
);

页面级错误边界

复制代码
<ErrorBoundary>
  <PerformanceReport />
</ErrorBoundary>

模块级错误边界

复制代码
<ErrorBoundary>
  <EchartsPanel />
</ErrorBoundary>

这样即使图表崩溃:

复制代码
<EchartsPanel />

也不会影响:

复制代码
<Table />
<Form />
<Menu />

9. 云鉴性能平台中的应用场景

根据你目前的 React + Ant Design + ECharts 项目,可以这样使用:

复制代码
<ErrorBoundary>
  <PerformanceOverview />
</ErrorBoundary>

<ErrorBoundary>
  <CpuCompareChart />
</ErrorBoundary>

<ErrorBoundary>
  <IssueTracking />
</ErrorBoundary>

例如:

复制代码
const data = undefined;

data.map(item => item.name);

出现:

复制代码
Cannot read properties of undefined (reading 'map')

此时:

  • PerformanceOverview 崩溃

  • ErrorBoundary 显示兜底页面

  • 其他模块正常显示

不会整页白屏。


10. 面试高频问题

Q:ErrorBoundary 是什么?

答:React 提供的错误捕获机制,用于捕获组件树中的运行时异常并展示降级 UI,避免整个应用崩溃。


Q:实现 ErrorBoundary 必须使用什么组件?

答:必须使用 Class Component,因为依赖:

复制代码
static getDerivedStateFromError()

componentDidCatch()

函数组件不能直接实现。


Q:ErrorBoundary 能捕获事件错误吗?

答:不能。

复制代码
onClick
onChange
setTimeout
Promise
async/await

中的异常需要自行处理。


一句话总结:

ErrorBoundary = React 的"try...catch(组件级)",专门用于捕获渲染阶段和生命周期中的错误,防止页面白屏。