148. 精读《React Error Boundaries》

本文深入探讨了React的ErrorBoundaries机制,详细介绍了如何使用ErrorBoundaries捕获子组件渲染时的错误,包括class组件和函数组件。文章还讨论了ErrorBoundaries的限制,如无法捕获回调事件和异步操作中的错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 的错误场景:

  1. 回调事件。由于回调事件执行时机不在渲染周期内,因此无法被 Error Boundary Catch 住,如有必要得自行 try/catch。

  2. 异步。比如 setTimeout 或 requestAnimationFrame,和第一条同理。

  3. 服务端渲染。

  4. 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 FQA 有很多宝藏,建议抽时间逐条阅读。

4 总结

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

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

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

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

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

关注 前端精读微信公众号

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值