将 ErrorBoundary 与异步生命周期函数一起使用

IT技术 javascript reactjs typescript asynchronous
2021-05-09 17:03:00

我想构建一个 React 组件,它在componentDidMount.

这是函数当前的样子(用 编写TypeScript):

async componentDidMount(): Promise<void> {
    try {
        const { props: { teamId }, state: { } } = this;
        const awaitableData = await UrlHelper.getDataAsync("some-fancy-url");

        // ... do something with awaitableData
    } catch(e) {
        console.log("Some error occured");
        throw e;
    }
}

所述render-function返回标记包裹在一个ErrorBoundary组件,它已componentDidCatch实现。但是,当等待的调用被拒绝并且我最终进入catch-block时,这永远不会被调用/触发

我在这里错过了什么?

2个回答

asyncfunction 是返回 promise 的常规函数​​的语法糖。async函数中的错误导致被拒绝的Promise。即使没有在任何地方处理被拒绝的Promise并导致Uncaught (in promise)错误,它也不会被错误边界捕获。

正如参考文献所述,

错误边界不会捕获以下错误:<...> 异步代码(例如 setTimeout 或 requestAnimationFrame 回调)

一个解决方案是在错误时更改组件状态并在下一次渲染时处理它。 render是可以同步重新抛出错误的地方。

一个例子

  state = { error: null };

  async componentDidMount() {
    try {
      await new Promise(resolve => setTimeout(resolve, 2000));
      throw new Error('Foo error');
    } catch (error) {
      this.setState({ error });
    }
  }

  render() {
    if (this.state.error) {
      throw this.state.error;
    }

    return (
      <p>Foo</p>
    );
  }

让我们看看文档

基本上它说:

错误边界是 React 组件,它在其子组件树中的任何位置捕获 JavaScript 错误,记录这些错误,并显示回退 UI 而不是崩溃的组件树。错误边界在渲染过程中、生命周期方法中以及在它们下面的整个树的构造函数中捕获错误。

所以基本上当你尝试使用 ASYNC/AWAIT 并且它失败时,它会在你的函数的 CATCH 端消失:

catch(e) {
    console.log("Some error occured");
    throw e;
}

并且该错误不会被componentDidMount. 实际上,如果您删除 try catch 方法,componentDidMount它将处理错误。