FrontendPrep
Menu
Topics
Questions
Guides
Challenges
Soon
Back to React Questions
reactMedium

React: How Error Boundaries Work

Understand how Error Boundaries catch rendering errors in React, when they fail to catch errors (asynchronous code, event handlers), and how fallback UIs are rendered.

React: How Error Boundaries Work

A common interview question for managing application stability is:

What is an Error Boundary in React? How do you implement one, and what are the limitations regarding what types of errors it can catch?

Historically, Javascript errors inside components corrupted React's internal state and caused it to emit cryptic errors on subsequent renders, often leading to a completely blank screen for the user. Error Boundaries provide a declarative way to catch rendering errors and display fallback interfaces.


1. What is an Error Boundary?

An Error Boundary is a React class component that catches JavaScript errors anywhere in its child component tree, logs those errors, and displays a fallback UI instead of crashing the whole component tree.

A class component becomes an error boundary if it defines one or both of these lifecycle methods:

  • static getDerivedStateFromError(error): Renders a fallback UI after an error has been thrown by updating state.
  • componentDidCatch(error, errorInfo): Logs error information to an external analytics or reporting service.
import React, { Component } from 'react';
 
export class ErrorBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
 
  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }
 
  componentDidCatch(error, errorInfo) {
    // Log error details to an external logging service
    console.error("ErrorBoundary caught an error:", error, errorInfo);
  }
 
  render() {
    if (this.state.hasError) {
      // Custom fallback UI
      return this.props.fallback || <h1>Something went wrong.</h1>;
    }
 
    return this.props.children;
  }
}

2. Declarative Usage

You wrap your component tree in the boundary. You can wrap the entire application or narrow sub-trees (like a sidebar or widget) to prevent a localized crash from breaking the entire page:

<ErrorBoundary fallback={<p>Header crashed but app is running!</p>}>
  <HeaderComponent />
</ErrorBoundary>
 
<main>
  <ErrorBoundary fallback={<p>Feed failed to load.</p>}>
    <FeedComponent />
  </ErrorBoundary>
</main>

3. Limitations of Error Boundaries

Error Boundaries do not catch errors inside:

  1. Event Handlers: Event handlers do not run during the render phase. If a button click throws an error, React still knows how to render the screen, so the boundary is not triggered.
  2. Asynchronous Code: Errors thrown in setTimeout, requestAnimationFrame, or async fetch callbacks will not be caught.
  3. Server-Side Rendering (SSR): Errors during SSR must be caught using server middleware.
  4. The Boundary itself: Errors thrown inside the ErrorBoundary component itself (rather than its children) cannot be caught by it.

Catching Event/Async Errors

To catch event or async errors using an Error Boundary, you must force the error back into the React render loop by setting state:

const [error, setError] = useState(null);
 
if (error) {
  throw error; // This will be caught by the parent Error Boundary!
}
 
const handleClick = async () => {
  try {
    await fetchData();
  } catch (err) {
    setError(err); // Triggers re-render and throws in render path
  }
};

Senior-Level Interview Answer

An Error Boundary is a class component that intercepts JavaScript runtime crashes in its descending child tree, acting as a declarative catch block for React component renders. It utilizes the static lifecycle method getDerivedStateFromError to catch exceptions during the render phase and mutate the state to display a fallback UI, alongside componentDidCatch to handle side effects like logging to tracking services. However, Error Boundaries do not catch errors in event handlers, async functions (like fetch or timers), SSR rendering cycles, or the boundary component itself. For async or event-driven operations, developers must catch errors manually and schedule state updates that throw the error during the subsequent render pass to force them up to the boundary.


Common Interview Mistakes

❌ Attempting to write a Functional Error Boundary

As of the latest React releases, there is no functional hook equivalent for getDerivedStateFromError or componentDidCatch. An Error Boundary component must be implemented using a class component, though it can wrap and render functional children.

❌ Relying on Error Boundaries for general business logic

Using boundaries to control application flow (e.g. routing users to a login screen when an unauthorized API response occurs) is an anti-pattern. They should only be used to handle unexpected rendering exceptions and keep the UI stable.


Key Takeaways

  • Class Component Requirement: Error boundaries must be class components; there are no hooks yet for derived errors.
  • Declarative Isolation: Wrapping individual widgets with boundaries prevents a single component crash from breaking the entire viewport.
  • Derived State: getDerivedStateFromError updates state to display fallbacks, while componentDidCatch handles error reporting.
  • Asynchronous Limit: They cannot catch exceptions thrown in async paths, timers, event listeners, or SSR runs.
  • Render Propagation: To route async failures to an error boundary, assign the error to state and throw it during the next render cycle.

Share this Resource

Help other developers level up by sharing this study guide.

More Technical Questions

Expand your mastery. Deep dive into other frontend interview challenges in this category.