Error Boundaries is a new feature introduced in React 16 to better handle unexpected errors that happen when a component tree is attempting to render.
The goal of Error Boundaries is to ensure that when an error does occur during render React has a way to catch that error in a component and handle it gracefully, rather than the component tree being broken and resulting in a white screen for the user. This all works by using a new lifecycle method on a Component
called componentDidCatch
:
class ErrorBoundary extends React.Component {
state = { hasError: false };
componentDidCatch(error, info) {
this.setState({ hasError: true });
}
render() {
if (this.state.hasError) {
return <h1 className="error">Error!</h1>;
}
return this.props.children;
}
}
const App = () => (
<ErrorBoundary>
<SomeComponent />
</ErrorBoundary>
);
The componentDidCatch
method receives two pieces of information, the error
that was thrown and info
which is the component stack trace. This sounds like information that would be really great for us to track in an error monitoring platform, like, say AppInsights!
Designing Our Component
Letâs create a generic âApp Insights Aware Error Boundaryâ component, which will allow us to place a boundary somewhere in our component tree but also be generic enough to use in multiple places. After all, we donât want a single error boundary, thatâd be akin to wrapping the whole application with a try
/catch
block and make it harder to handle errors-at-the-source.
import React from "react";
import { SeverityLevel } from "@microsoft/applicationinsights-web";
class AppInsightsErrorBoundary extends React.Component {
state = { hasError: false };
componentDidCatch(error, info) {
this.setState({ hasError: true });
this.props.appInsights.trackException({
error: error,
exception: error,
severityLevel: SeverityLevel.Error,
properties: { ...info }
});
}
render() {
if (this.state.hasError) {
const { onError } = this.props;
return typeof onError === "function"
? onError()
: React.createElement(onError);
}
return this.props.children;
}
}
Our component will take two props
, appInsights
and onError
. The first is the AppInsights instance you would initialise within an application, as we did in the last post, the other is the component to render or a function to return a component.
Using Our Error Boundary
Iâve created a demo application using the Gastby eCommerce starter kit (like last time) that shows how you can use an Error Boundary (source code is on my GitHub).
Since it turns out itâs hard to create a reproducible error in a well-written application Iâve created a fake error scenario, basically whenever you try to add more than 1 item to the cart itâll throw an error during render
(error in codebase).
Before seeing the error boundary in action, what would it look like if we didnât have one?
Without the error boundary, we end up with a blank screen because the whole component tree has become corrupt.
Now we wrap our âbuggyâ component with an error boundary and if we click the âAdd to Cartâ button we successfully added to cart, but if when you try to increase the number in the text box it throws an error and the error boundary is displayed.
How does that look in code? Well, we wrap the component we want with the error boundary (source):
<ErrorBoundary onError={() => <h1>I believe something went wrong</h1>}>
<AddToCart productId={id} />
</ErrorBoundary>
Because Iâve got a really basic component to put in when thereâs an error, Iâm just created an inline function component, but you might want to provide a proper component reference instead.
Inspecting Errors in AppInsights
By logging into the Azure Portal and navigating to your AppInsights resource youâll be able to filter the data to the exceptions youâve captured:
The information might be a little tricky to read if youâre using a minified bundle, but to help with that you can upload your Source Map and have it help give you more detailed information in the logs!
Conclusion
AppInsights will automatically capture unhandled errors that reach the onError
event in the browser, but when using React you want to do something thatâll allow you to handle the component tree failing to render, which is where Error Boundaries come into play. We can then combine this with AppInsights to have our Error Boundary log those handled errors, you could even provide additional information to the properties of the tracked events if desired.
Top comments (1)
What an interesting use of React! As someone who is working on an app professionally that will eventually live on Azure, this idea could prove useful.