Recently I was implementing a pdf reader for a magazine on a page, I tested it on the desktop browser and everything worked perfectly.
The problem occurred on mobile, because after going through a few pages of the pdf, the site crashed completely: "Application error: a client-side exception has occurred (see the browser console for more information).".
Content summary
I'm not going to talk about the solution, but about how to prevent your application crashing completely in these cases, using the concept of Error Boundary to present an alternative UI in the case of an error.
Before React 16, an error in any component could result in the entire application crashing, as the error was propagated (intentionally, it's not a bug, it's a featureπ«£), completely breaking the site and creating a bad user experience. With the arrival of React 16, Error Boundaries were introduced, allowing developers to capture and handle errors in specific components, without bringing down the entire application.
What are Error Boundaries? π
Error Boundaries is a React component that catches JavaScript errors in its child components, logs those errors and displays a fallback interface instead of the failed component, working like a *catch{} for components.
Currently, it's only available as a class component and, so far, there's no evidence of the React team wanting to change this (ok, officially there isn't, but you'll find ways to do this both manually and with external libs and I'll talk about that later).
Code Example:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
logErrorToService(error, info.componentStack);
}
render() {
if (this.state.hasError) {
return <h1>Something has gone wrong.</h1>;
}
return this.props.children;
}
}
Let's better understand the role of the functions:
- getDerivedStateFromError: This static function is used to update the local state of the component and render a fallback UI after an error.
- componentDidCatch: This method is triggered after an error is caught by the Error Boundary. It is useful for logging errors or side effects.
When using Error Boundary in your application, wrap the components you want to protect:
<ErrorBoundary>
<Component />
</ErrorBoundary>
You can also involve the entire application or you can involve the content of the site excluding the layout or even just routes, it all depends on the design you choose and which makes the most sense in your context.
When to use and when not to use π
When to use
- In non-critical components or functionalities.
- When incorporating widgets or third-party libraries.
When not to use
- For expected errors (such as known API errors).
- Within event handlers.
- For errors that should be handled specifically and not generically.
- Asynchronous code: Error Boundaries do not catch errors in asynchronous operations outside of React components, such as
setTimeout
orrequestAnimationFrame
. To handle errors in asynchronous operations inside components, you must usetry/catch
blocks. - Server-side rendering
- Errors thrown in the Error Boundary itself.
Optionals: π
- Integrate Error Boundaries with error monitoring solutions for quick identification and correction, you can integrate with Sentry or Exceptionless for example.
- Test your Error Boundaries to ensure that they work as expected in different scenarios.
Third-party libraries: react-error-boundary
π
While React's native Error Boundaries are sufficient to handle these needs, some third-party libraries have been developed to simplify and enrich this functionality. One of the most popular is react-error-boundary
.
Main benefits
Simplified API: With react-error-boundary
, you can create an error boundary with a simple fallback function, without the need to create a component class, and it offers several other possibilities, which I won't go into today.
example with react-error-boundary
:
import { ErrorBoundary } from 'react-error-boundary'
function FallbackComponent({ error }) {
return <div>An error has occurred: {error.message}</div>
}
<ErrorBoundary FallbackComponent={FallbackComponent}>
<Component />
</ErrorBoundary>
Additional Hooks and Utilities: The library offers the useErrorHandler
hook, which allows you to catch and handle errors within functional components and custom functions.
Automatic Restart: With the onReset
property, you can define how the component should restart itself after an error.
Top comments (0)