Error Boundaries

Back

Loading concept...

🛡️ Error Boundaries: Your App’s Safety Net

The Story of the Brave Firefighter

Imagine your React app is a big, beautiful building full of rooms. Each room is a component. Sometimes, a room catches fire (an error happens). Without protection, the whole building burns down!

Error Boundaries are like firefighters 🚒 stationed at key doors. When fire breaks out in one room, they contain it there. The rest of the building stays safe!


🎯 What You’ll Master

  1. Error boundary basics - What they are and why we need them
  2. Class component lifecycle - The special powers only class components have
  3. componentDidCatch - Catching the fire
  4. getDerivedStateFromError - Raising the alarm
  5. Error fallback UI - Showing a friendly “oops” message

1. Error Boundary Basics

What is an Error Boundary?

Think of it like a safety bubble around your components.

// Without Error Boundary:
// One broken component = ENTIRE APP CRASHES! 😱

// With Error Boundary:
// One broken component = Only that part shows
// a friendly error message. App keeps working! ✅

The Simple Truth

An Error Boundary is a special React component that catches JavaScript errors in its child components and displays a fallback UI instead of crashing.

Real-Life Example

<ErrorBoundary>
  <UserProfile />   {/* If this crashes... */}
  <UserSettings />  {/* ...these still work! */}
</ErrorBoundary>

Key Rule: Error Boundaries catch errors in:

  • ✅ Rendering
  • ✅ Lifecycle methods
  • ✅ Constructors of child components

They DON’T catch errors in:

  • ❌ Event handlers (use try-catch)
  • ❌ Async code (like setTimeout)
  • ❌ Server-side rendering
  • ❌ Errors in the boundary itself

2. Class Component Lifecycle

Why Class Components?

Here’s a secret: Error Boundaries MUST be class components. React hooks can’t do this yet!

// ✅ This works - Class component
class ErrorBoundary extends React.Component {
  // Special error-catching powers here!
}

// ❌ This CANNOT be an error boundary
function ErrorBoundary() {
  // No error-catching powers for functions! 😢
}

The Lifecycle Flow

graph TD A["Component Mounts"] --> B["Child Renders"] B --> C{Error Occurs?} C -->|Yes| D["getDerivedStateFromError"] D --> E["componentDidCatch"] E --> F["Show Fallback UI"] C -->|No| G["App Works Normally"]

Basic Class Structure

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

  // Two special methods make this
  // an Error Boundary...
}

3. getDerivedStateFromError

The Alarm System 🚨

This method is like your smoke detector. The moment smoke appears, it beeps!

static getDerivedStateFromError(error) {
  // The fire is detected!
  // Return new state to trigger re-render
  return { hasError: true };
}

Key Facts

Feature Description
Type Static method
When called During render phase
Purpose Update state
Side effects ❌ Not allowed

Complete Example

class ErrorBoundary extends React.Component {
  state = { hasError: false };

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

  render() {
    if (this.state.hasError) {
      return <h1>Oops! Something broke.</h1>;
    }
    return this.props.children;
  }
}

4. componentDidCatch

The Investigation Team 🔍

After the alarm sounds, investigators arrive. They take notes about what went wrong.

componentDidCatch(error, errorInfo) {
  // error: What went wrong
  // errorInfo: Where it went wrong

  console.log('Error:', error);
  console.log('Stack:', errorInfo.componentStack);

  // Send to error tracking service
  logErrorToService(error, errorInfo);
}

The Two Parameters

componentDidCatch(error, errorInfo) {
  // error.message = "Cannot read property..."
  // error.name = "TypeError"

  // errorInfo.componentStack =
  //   "in BrokenComponent"
  //   "in ErrorBoundary"
  //   "in App"
}

When to Use What?

graph TD A["Error Happens"] --> B["getDerivedStateFromError"] B --> C["Updates state for fallback UI"] A --> D["componentDidCatch"] D --> E["Logs error details"] D --> F["Sends to analytics"]
Method Purpose Side Effects?
getDerivedStateFromError Update UI ❌ No
componentDidCatch Log errors ✅ Yes

5. Error Fallback UI

Making Errors Friendly 💝

When things break, users should see something helpful—not a blank screen!

Simple Fallback

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-box">
          <h2>😅 Oops!</h2>
          <p>Something went wrong.</p>
          <button onClick={() =>
            this.setState({ hasError: false })
          }>
            Try Again
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

Custom Fallback Component

// Reusable error boundary with custom UI
class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null };

  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    logToService(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      // Use custom fallback if provided
      return this.props.fallback || (
        <DefaultErrorUI />
      );
    }
    return this.props.children;
  }
}

// Usage:
<ErrorBoundary fallback={<MyErrorPage />}>
  <RiskyComponent />
</ErrorBoundary>

Strategic Placement

Place error boundaries at different levels:

<App>
  <ErrorBoundary> {/* Whole app safety */}
    <Header />
    <ErrorBoundary> {/* Main content only */}
      <MainContent />
    </ErrorBoundary>
    <ErrorBoundary> {/* Sidebar only */}
      <Sidebar />
    </ErrorBoundary>
    <Footer />
  </ErrorBoundary>
</App>

🎁 Putting It All Together

Here’s a complete, production-ready Error Boundary:

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

  static getDerivedStateFromError(error) {
    // Step 1: Update state for fallback UI
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    // Step 2: Log the error
    this.setState({ errorInfo });
    console.error('Caught error:', error);

    // Send to your error tracking
    // logToService(error, errorInfo);
  }

  handleReset = () => {
    this.setState({
      hasError: false,
      error: null,
      errorInfo: null
    });
  };

  render() {
    if (this.state.hasError) {
      return (
        <div style={{ padding: '20px' }}>
          <h2>🛡️ Something went wrong</h2>
          <p>{this.state.error?.message}</p>
          <button onClick={this.handleReset}>
            Try Again
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

export default ErrorBoundary;

🚀 Quick Recap

Concept Remember This
Error Boundary Safety bubble for components
Class Component Required! Hooks can’t do this
getDerivedStateFromError Returns new state (the alarm)
componentDidCatch Logs errors (the investigation)
Fallback UI Friendly message when things break

🎭 The Firefighter’s Motto

“Catch errors at the door, so the whole house doesn’t burn down.”

Error Boundaries are your app’s first responders. Place them wisely, and your users will never see a blank white screen of doom again!

You’ve got this! 🎉

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.