Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use ErrorBoundary together with asynchronous lifecycle-functions

I want to build a React-component which loads the data asynchronously on componentDidMount.

This is what the function currently looks like (written in 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;
    }
}

The render-function returns the markup wrapped in a ErrorBoundary component, which has componentDidCatch implemented. However, this is never called/triggered when the awaited call is rejected and I end up in the catch-block.

What am I missing here?

like image 811
KingKerosin Avatar asked Apr 25 '18 12:04

KingKerosin


People also ask

How do you trigger ErrorBoundary?

With the new feature in React, developers can test the Error Boundaries by a toggle error button, added to the DevTools. When we click on the toggle error button on the component labeled 'Inner Component', Error boundary is triggered.

Can we use error boundary in functional component?

Only class components can be error boundaries. In practice, most of the time you'll want to declare an error boundary component once and use it throughout your application. Note that error boundaries only catch errors in the components below them in the tree. An error boundary can't catch an error within itself.

How do you handle error boundaries in functional components?

In order to use Error Boundary in Functional Component, I use react-error-boundary. When we run this application, we will get a nice error display form the content of ErrorHandler component. React error boundary catches any error from the components below them in the tree.

Which methods are called when the state or props of a component is changed?

An update can be caused by changes to props or state. These methods are called in the following order when a component is being re-rendered: static getDerivedStateFromProps() shouldComponentUpdate() render()


1 Answers

async function is syntactic sugar for a regular function that returns a promise. An error in async function results in rejected promise. Even if rejected promise isn't handled anywhere and results in Uncaught (in promise) error, it is not caught by error boundaries.

As the reference states,

Error boundaries do not catch errors for: <...> Asynchronous code (e.g. setTimeout or requestAnimationFrame callbacks)

A solution is to change component state on error and handle it on next render. render is the place where error can be re-thrown synchronously.

An example:

  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>
    );
  }
like image 125
Estus Flask Avatar answered Sep 24 '22 08:09

Estus Flask