Error Boundaries

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

Error Boundaries

In the past, JavaScript errors inside React components used to corrupt React’s internal state and cause it to emit cryptic errors on next renders. Worse, an error in one small component would completely crash the entire application, leaving the user with a blank white screen.

Error Boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of crashing the whole app.

Important Restrictions

Currently, Error Boundaries must be Class Components. There is no equivalent React Hook (like useErrorBoundary) available yet.

Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

Error Boundaries DO NOT catch errors for:

  1. Event handlers (e.g., a crash inside an onClick function).
  2. Asynchronous code (e.g., setTimeout or a failing fetch request).
  3. Server-side rendering.
  4. Errors thrown in the error boundary itself.

How to Create an Error Boundary

A class component becomes an error boundary if it defines either (or both) of the lifecycle methods static getDerivedStateFromError() or componentDidCatch().

import React from 'react';

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

  // 1. Update state so the next render shows the fallback UI.
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  // 2. You can also log the error to an error reporting service
  componentDidCatch(error, errorInfo) {
    console.error("Uncaught error:", error, errorInfo);
    // logErrorToMyService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong. Please refresh the page.</h1>;
    }

    // If no error, render the children normally
    return this.props.children; 
  }
}

export default ErrorBoundary;

Where to Place Error Boundaries

You can wrap Error Boundaries at the very top level of your app to display a “Something went wrong” message to the user, similar to a server-side 500 page.

<ErrorBoundary>
  <App />
</ErrorBoundary>

However, a better practice is to wrap individual widgets or sections of your application. If a minor component crashes (like a Twitter sidebar or a single chart in a dashboard), you don’t want the entire application to disappear.

<main>
  <Sidebar />
  <Content />
  
  {/* If the AdWidget crashes, the rest of the page still works perfectly */}
  <ErrorBoundary>
    <AdWidget />
  </ErrorBoundary>
</main>

react-error-boundary Library

Because writing class components is tedious in modern React, most developers use the widely popular react-error-boundary library. It provides a simple component and a hook to achieve the same result without writing classes.

import { ErrorBoundary } from 'react-error-boundary';

function Fallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  );
}

// Usage
<ErrorBoundary FallbackComponent={Fallback}>
  <MyWidget />
</ErrorBoundary>

Interview Questions

Q: What is an Error Boundary?
A: An Error Boundary is a special React component that catches JavaScript errors anywhere in its child component tree, logs those errors, and displays a graceful fallback UI instead of allowing the error to crash the entire application to a blank white screen.

Q: Can functional components act as Error Boundaries?
A: No. Currently, only Class components that implement the static getDerivedStateFromError() or componentDidCatch() lifecycle methods can act as Error Boundaries.