javascript - Använd ErrorBoundary tillsammans med asynkrona livscykelfunktioner


Jag vill bygga en React-komponent som laddar data asynkront på componentDidMount.

Så här ser funktionen för närvarande ut (skriven i 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-funktionen returnerar markeringen innesluten i en ErrorBoundary-komponent, som har componentDidCatch implementerad. Men detta kallas/utlöses aldrig när det väntade anropet avvisas och jag hamnar i catch-blocket.

Vad missar jag här?

Svar #1

async-funktion är syntaktiskt socker för en vanlig funktion som returnerar ett löfte. Ett fel i async-funktionen resulterar i ett avvisat löfte. Även om det avvisade löftet inte hanteras någonstans och resulterar i ett Uncaught (in promise)-fel, fångas det inte av felgränser.

Som referensen anger,

Felgränser fångar inte fel för: <...> Asynkron kod (t.ex. setTimeout eller requestAnimationFrame-callbacks)

En lösning är att ändra komponentens tillstånd vid fel och hantera det vid nästa rendering. render är platsen där fel kan kastas om synkront.

Ett exempel:

  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>
    );
  }

Relaterade artiklar