React 错误处理与稳定性:Error Boundary、日志与降级策略
业务代码写多了,就会遇到这样的问题:某个组件里一个异常没处理好,把整棵应用直接打挂。
和其说是在写新功能,不如说是在为「出问题时还能撑住场面」做准备。
Error Boundary:拦住渲染阶段的异常
Error Boundary 只能在 class 组件里实现,但可以用来保护一整颗子树:
1type ErrorBoundaryProps = {
2 fallback: React.ReactNode;
3 onError?: (error: Error, info: React.ErrorInfo) => void;
4};
5
6type ErrorBoundaryState = {
7 hasError: boolean;
8};
9
10class ErrorBoundary extends React.Component<
11 ErrorBoundaryProps,
12 ErrorBoundaryState
13> {
14 constructor(props: ErrorBoundaryProps) {
15 super(props);
16 this.state = { hasError: false };
17 }
18
19 static getDerivedStateFromError() {
20 return { hasError: true };
21 }
22
23 componentDidCatch(error: Error, info: React.ErrorInfo) {
24 this.props.onError?.(error, info);
25 }
26
27 render() {
28 if (this.state.hasError) {
29 return this.props.fallback;
30 }
31 return this.props.children;
32 }
33}
用法很直接:
1<ErrorBoundary fallback={<div>出错了,请稍后重试</div>}>
2 <MainApp />
3</ErrorBoundary>
或者只包住某些「风险较高」的区域,比如富文本编辑器、可视化画布等。
错误边界能捕获什么,不能捕获什么
能捕获的:
- 渲染过程中抛出的异常;
- 生命周期方法里的异常;
- 由这些组件触发的事件处理函数里的同步异常。
不能捕获的:
- 异步回调里的异常(setTimeout、Promise.then 等);
- 服务端渲染(SSR)阶段抛出的错误;
- 自身 Error Boundary 组件内部抛出的错误。
因此,对异步请求、手动抛错的业务逻辑,仍然需要自己做 try/catch 或在数据层做统一处理。
日志与监控:把错误送到正确的地方
错误本身只是现象,更关键的是在生产环境里能及时感知和定位。
Error Boundary 的 onError 钩子可以用来接入日志系统:
1function logError(error: Error, info: React.ErrorInfo) {
2 // 发送到日志系统,例如 Sentry、自研监控等
3}
4
5<ErrorBoundary
6 fallback={<ErrorPage />}
7 onError={logError}
8>
9 <MainApp />
10</ErrorBoundary>
合适的策略通常包括:
- 给错误打上应用版本、用户信息(脱敏后)和路由信息;
- 区分前端渲染错误与后端接口错误;
- 对重复的错误进行聚合,避免被单一错误刷屏。
降级策略:局部挂了不代表整站崩盘
错误不可避免,重点是「挂了之后用户还能不能做事」。
常见的降级分几层:
- 局部降级:某个 widget 出错,只替换这块区域为简化版本或提示信息;
- 页面级降级:某个页面关键逻辑出错,引导回到上一页或首页;
- 全局降级:全局 Error Boundary 捕获到异常时,展示一个简单但可用的 fallback(例如仅导航 + 反馈入口)。
举个局部降级的例子:
1<ErrorBoundary fallback={<div>图表加载失败</div>}>
2 <Chart />
3</ErrorBoundary>
Chart 挂了,页面其他部分照样可用。
与异步请求结合
大部分真实场景里的错误,来自于异步请求或业务规则检查。
这类错误更适合在数据层做处理,而不是试图让 Error Boundary 去兜:
- 对于请求错误:在数据 fetching 层(如 React Query 的
onError)统一收集和提示; - 对于业务错误:约定好错误结构和展示方式(toast、inline 提示等),前端只负责按结构展示。
这样一来:
- Error Boundary 主要负责意料之外的渲染崩溃;
- 数据层负责可预期的失败分支。
小结
- Error Boundary 是 React 里处理渲染阶段异常的最后一道防线,适合按区域包裹子树,配合统一的错误日志上报。
- 它不能替代异步错误处理,setTimeout、Promise 等回调里的异常需要在业务逻辑或数据层自己兜住。
- 合理设计局部/页面/全局三层降级策略,可以让应用在局部出问题时仍保持可用。
- 把「意料之外的错误」交给 Error Boundary,「可预期的失败分支」交给数据层和业务逻辑,各司其职更容易维护。