Errors are frustrating. But you know what’s more frustrating? A simple error that breaks your entire app.
Let’s talk about this in terms of building a component in React. So, suppose you are creating a login form. You have designed a nice component and finished writing the logic for the login functionality as well.
Let’s assume, you somehow made a mistake in the logic for the toggle password visibility function like I did while I was working on my hobby project a year ago to prepare for my interview at Elastik Teams.
In the above image, I have a login component and a navbar component on the same page then even if the navbar component is working fine still an error from the login component would break the entire application. By breaking the entire application, I mean that it won’t render the login component as well as the navbar component because of the error.
This is actually what happened when I saw the blank screen(in production deployment) that left me confused. In development mode, you will be able to see the error overlay in the browser.
These types of runtime errors can be handled gracefully using error boundaries.
The purpose of an error boundary is to prevent an error from occurring in one component and taking down an entire application.
So, what is an error boundary?
An error boundary is a special component that helps to handle errors that might occur in a part of a React application. Error boundaries can help you to catch the error in the component and display a simple message to let users know that something went wrong.
Error boundaries can be created using a class component but in this article, I will be using the react-error-boundary package in function components.
Let’s talk more about this with the help of an example -
Below is a simple React component that displays a string,
// A Working Component
import React from 'react';
const Working = () => {
return <p>This totally works fine!</p>;
};
export default Working;
Here’s another component that displays the given status in uppercase format,
import React from 'react';
const ShowStatus= ({ status }) => {
return <p>I'm {status.toUpperCase()}.</p>;
};
export default ShowStatus;
Here I am rendering both components in the main file,
import React from 'react';
import Working from './components/Working';
import ShowStatus from './components/ShowStatus';
export default function App() {
return (
<div>
<Working />
<ShowStatus/>
</div>
);
}
If I run the app, it won’t work because the ShowStatus
component is expecting a status prop that I have not provided to it.
Hence I’ll see the below error in the browser
React also logs the error in the console as you can see in the below image,
But since my Working
component didn’t have any error in it, React didn’t render it as well on the screen.
This can be prevented using a simple error boundary. Let’s modify the code to introduce an error boundary and handle this error gracefully.
I’ll be using the react-error-boundary
package from NPM.
After modifying the code to handle errors using the error boundary, it will look like this,
import React from 'react';
import Working from './components/Working';
import ShowStatus from './components/ShowStatus';
import Fallback from './components/Fallback';
import { ErrorBoundary } from 'react-error-boundary';
export default function App() {
return (
<div>
<Working />
<ErrorBoundary FallbackComponent={Fallback}>
<ShowStatus />
</ErrorBoundary>
</div>
);
}
The react-error-boundary
package provides a reusable wrapper that can be wrapped around any component.
In the above example, I have added an error boundary to the ShowStatus
component since I am aware that the error is originating from that component.
The ErrorBoundary
component takes a FallbackComponent
as a prop that will be rendered in case of an error. The FallbackComponent
receives occurred error as a prop. This error object contains information such as an error message that can be used to display what went wrong in the component.
The fallback component can be customized to display a loader, an error message, or anything else.
Here is a simple fallback component that I have created that simply displays the error message on the screen.
import React from 'react';
const Fallback = ({ error }) => {
return (
<div>
<p>{error.message}</p>
</div>
);
};
export default Fallback;
After adding the error boundary then instead of breaking the entire application, I can see the following result in the browser.
As you can see, React rendered the Working
component and the Fallback
component with the error message instead of showing a blank screen or breaking the whole application.
In this way, error boundaries can be used to catch errors from anywhere in the child components, log the errors and display a fallback UI.
You can use different error boundaries for separate components or use the same error boundary for multiple components as well. The choice is yours.
Instead of using error boundaries, this could've also been resolved using the try-catch mechanism but since error boundary provides a cleaner and simplified way, it is suitable to go with this instead of the traditional try-catch way.
There are some limitations to this as well as error boundaries do not catch errors for
- Event handlers
- Asynchronous code (e.g.
setTimeout
orrequestAnimationFrame
callbacks) - Server-side rendering
- Errors that are thrown in the error boundary itself (rather than its children)
TL;DR
Error boundaries are really helpful because they can prevent your whole app from crashing when something goes wrong in a small part of the application. They can also help you to find and fix errors in the code more easily so you can make your app work better for your users.
You can read more about error boundaries here.
Top comments (0)