In the previous chapter we looked at how to report API errors to Sentry in our React app. Now let’s report all those unexpected errors that might happen using a React Error Boundary.

An Error Boundary is a component that allows us to catch any errors that might happen in the child components tree, log those errors, and show a fallback UI.

Create an Error Boundary

It’s incredibly straightforward to setup. So let’s get started.

Change indicator Add the following to src/components/ErrorBoundary.tsx in your frontend/ directory.

import React from "react";
import {logError} from "../lib/errorLib";
import "./ErrorBoundary.css";

export default class ErrorBoundary extends React.Component<any, any> {
  state = { hasError: false };

  static getDerivedStateFromError(_error: unknown) {
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: any) {
    logError(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <div className="ErrorBoundary text-center">
        <h3>Sorry there was a problem loading this page</h3>
      </div>;
    } else {
      return this.props.children;
    }
  }
}

The key part of this component is the componentDidCatch and getDerivedStateFromError methods. These get triggered when any of the child components have an unhandled error. We set the internal state, hasError to true to display our fallback UI. And we report the error to Sentry by calling logError with the error and errorInfo that comes with it.

Let’s include some simple styles for this.

Change indicator Create a src/components/ErrorBoundary.css file and add:

.ErrorBoundary {
  padding-top: 100px;
}

The styles we are using are very similar to our NotFound component. We use that when a user navigates to a page that we don’t have a route for.

Use the Error Boundary

To use the Error Boundary component that we created, we’ll need to add it to our app component.

Change indicator Find the following in src/App.tsx.

<AppContext.Provider value={{ isAuthenticated, userHasAuthenticated } as AppContextType}>
  <Routes />
</AppContext.Provider>

Change indicator And wrap it with our ErrorBoundary:

<ErrorBoundary>
  <AppContext.Provider value={{ isAuthenticated, userHasAuthenticated } as AppContextType}>
    <Routes />
  </AppContext.Provider>
</ErrorBoundary>

Change indicator Also, make sure to import it in the header of src/App.js.

import ErrorBoundary from "./components/ErrorBoundary";

And that’s it! Now an unhandled error in our containers will show a nice error message. While reporting the error to Sentry.

Commit the Changes

Change indicator Let’s commit these to Git (but don’t push yet).

$ git add .;git commit -m "Adding React error reporting";

Test the Error Boundary

Before we move on, let’s do a quick test.

Replace the following in src/containers/Home.tsx.

{isAuthenticated ? renderNotes() : renderLander()}

With these faulty lines:

{isAuthenticated ? renderNotes() : renderLander()}
{ isAuthenticated.none.no }

Now in your browser you should see something like this.

React error message

While developing, React doesn’t show your Error Boundary fallback UI by default. To view that, hit the close button on the top right.

React Error Boundary fallback UI

Since we are developing locally, we don’t report this error to Sentry. But let’s do a quick test to make sure it’s hooked up properly.

Replace the following from the top of src/lib/errorLib.js.

const isLocal = process.env.NODE_ENV === "development";

With:

const isLocal = false;

Now if we head over to our browser, we should see the error as before. And we should see the error being reported to Sentry as well! It might take a moment or two before it shows up.

First error in Sentry

And if you click through, you can see the error in detail.

Error details in Sentry

Now our React app is ready to handle the errors that are thrown its way!

Let’s cleanup all the testing changes we made above.

$ git checkout .

Push the Changes

Change indicator Let’s also push these changes to GitHub and deploy our app.

$ git push

Next, let’s look at how to handle errors in our serverless app.