当前期刊数: 148

1 引言

Error Boundaries 是 React16 提出来用来捕获渲染时错误的概念,今天我们一起读一读 A Simple Guide to Error Boundaries in React 这篇文章,了解一下这个重要机制。

2 概述

Error Boundaries 可以用来捕获渲染时错误,API 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyErrorBoundary extends Component {
state = {
error: null,
};

static getDerivedStateFromError(error) {
// 更新 state,下次渲染可以展示错误相关的 UI
return { error: error };
}

componentDidCatch(error, info) {
// 错误上报
logErrorToMyService(error, info);
}

render() {
if (this.state.error) {
// 渲染出错时的 UI
return <p>Something broke</p>;
}
return this.props.children;
}
}
  • static getDerivedStateFromError: 在出错后有机会修改 state 触发最后一次错误 fallback 的渲染。
  • componentDidCatch: 用于出错时副作用代码,比如错误上报等。

这两种方法中任意一个被定义时,这个组件就会成为 Error Boundary 组件,可以阻止子组件渲染时报错。

最后作者还提出一个建议,建议将 Error Boundary 单独作为一个组件,而不是将错误监听方法与业务组件耦合,一方面考虑到复用,另一方面则因为错误检测只对子组件生效。

好吧,其实 React 官方文档比这篇文章介绍的详细的多得多,原文介绍到此结束。

3 精读

React Error Boundaries 官方文档 里提到了四种无法 Catch 的错误场景:

  1. 回调事件。由于回调事件执行时机不在渲染周期内,因此无法被 Error Boundary Catch 住,如有必要得自行 try/catch。
  2. 异步。比如 setTimeoutrequestAnimationFrame,和第一条同理。
  3. 服务端渲染。
  4. Error Boundary 组件自身触发的错误。因为只能捕获其子组件的错误。

这也是使用 Error Boundaries 最容易有疑问的地方。除了上面的情况,笔者结合自身经验再列举几种异常边界场景。

无法捕获编译时错误

很明显,即便是 React 官方 API Error Boundary 也只能捕获运行时错误,而对编译时错误无能为力。

编译时错误包括不限于编译环境错误、运行前的框架错误检查提示、TS/Flow 类型错误等,这些都是 Error Boundary 无法捕获的,而且没有更好的办法 Catch 住,遇到编译错误就在编译时解决吧,仅关注运行时错误就好了。

可以作用于 Function Component

虽然函数式组件无法定义 Error Boundary,但 Error Boundary 可以捕获函数式组件的错误,因此可以曲线救国:

1
2
3
4
5
6
7
8
9
10
11
12
13
// ErrorBoundary 组件
class ErrorBoundary extends React.Component {
// ...
}

// 可以捕获所有组件异常,包括 Function Component 的子组件
const App = () => {
return (
<ErrorBoundary>
<Child />
</ErrorBoundary>
);
};

对 Hooks 也可生效

对于 Hooks 中异常也可以生效,比如下面的代码:

1
2
3
4
5
6
7
8
9
const Child = (props) => {
React.useEffect(() => {
console.log(1);
props.a.b;
console.log(2);
}, [props.a.b]);

return <div />;
};

要注意的是,出现在 deps 中的错误会立即被 Catch,导致 console.log(1) 都无法打印。但如果是下面的代码,则可以打印出 console.log(1),无法打印出 console.log(2):

1
2
3
4
5
6
7
8
9
const Child = (props) => {
React.useEffect(() => {
console.log(1);
props.a.b;
console.log(2);
}, []);

return <div />;
};

所以 React 官网的这句话并不是指 Error Boundary 对 Hooks 不生效,而是指 Error Boundary 无法以 Hooks 方式指定,对功能是没有影响的:

componentDidCatch and getDerivedStateFromError: There are no Hook equivalents for these methods yet, but they will be added soon.

所以这里的理解要注意一下,另外 React 官方文档 Hooks FAQ 有很多宝藏,建议抽时间逐条阅读。

4 总结

Error Boundary 可以捕获所有子元素渲染时异常,包括 render、各生命周期函数,但也有很多使用限制,希望你可以正确使用它。

错误捕获也不是万能的,更多时候我们要避免并及时修复错误,通过错误捕获降低出错时对用户体验的影响,并在第一时间内监控起来并快速修复。

最后,你有明明正确使用了 Error Boundary 却依然无法 Catch 住的错误 Case 吗?

讨论地址是:精读《React Error Boundaries》 · Issue ##246 · dt-fe/weekly

如果你想参与讨论,请 点击这里,每周都有新的主题,周末或周一发布。前端精读 - 帮你筛选靠谱的内容。

关注 前端精读微信公众号

版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证


本站由 钟意 使用 Stellar 1.28.1 主题创建。
又拍云 提供CDN加速/云存储服务
vercel 提供托管服务
湘ICP备2023019799号-1
总访问 次 | 本页访问