精读《React Error Boundaries》
1 引言
Error Boundaries 是 React16 提出来用来捕获渲染时错误的概念,今天我们一起读一读 A Simple Guide to Error Boundaries in React 这篇文章,了解一下这个重要机制。
2 概述
Error Boundaries 可以用来捕获渲染时错误,API 如下:
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 的错误场景:
- 回调事件。由于回调事件执行时机不在渲染周期内,因此无法被 Error Boundary Catch 住,如有必要得自行 try/catch。
- 异步。比如
setTimeout
或requestAnimationFrame
,和第一条同理。 - 服务端渲染。
- Error Boundary 组件自身触发的错误。因为只能捕获其子组件的错误。
这也是使用 Error Boundaries 最容易有疑问的地方。除了上面的情况,笔者结合自身经验再列举几种异常边界场景。
无法捕获编译时错误
很明显,即便是 React 官方 API Error Boundary
也只能捕获运行时错误,而对编译时错误无能为力。
编译时错误包括不限于编译环境错误、运行前的框架错误检查提示、TS/Flow 类型错误等,这些都是 Error Boundary
无法捕获的,而且没有更好的办法 Catch 住,遇到编译错误就在编译时解决吧,仅关注运行时错误就好了。
可以作用于 Function Component
虽然函数式组件无法定义 Error Boundary
,但 Error Boundary
可以捕获函数式组件的错误,因此可以曲线救国:
// ErrorBoundary 组件
class ErrorBoundary extends React.Component {
// ...
}
// 可以捕获所有组件异常,包括 Function Component 的子组件
const App = () => {
return (
<ErrorBoundary>
<Child />
</ErrorBoundary>
);
};
对 Hooks 也可生效
对于 Hooks 中异常也可以生效,比如下面的代码:
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)
:
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 许可证)
发表评论 (审核通过后显示评论):