Error boundaries should return something simple and safe instead of children in error conditions

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the react category.

Last Updated: 2024-04-18

In my react app, I used an error boundary as so:

return (
  <ErrorBoundary>
    <Router>
      <Switch>
        <Route path="/" exact component={HomeScreen} />
      </Switch>
    </Router>
  </ErrorBoundary>
  )

And here's the code for the ErrorBoundary component:

import React from "react";

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      hasError: false
    };
  }

  componentDidCatch(error, info) {
    this.setState({
      hasError: true
    })
  }

  render() {
    if (this.state.hasError) {
      alert("Got bug");
    }

    // Render whatever this component was wrapping.
    return this.props.children;
  }
}

Unfortunately when I hit an error, my error boundary component infinitely looped, constantly alerting, and grinding responsiveness down to naught.

The fix was to explicitly return something safe when the error occurred, as opposed to re-rendering the broken code and triggering problems all over again:

render() {
  if (this.state.hasError) {
    return <div>
        <h1>Encountered an error. </h1>
        <p>Please open your JavaScript logs for more info.</p>
      </div>
  }
    // Render whatever this component was wrapping.
  return this.props.children;
}

Lesson

When creating error boundaries in React, do not render the child components (which contain the errors). Instead render something simple and safe.