Error boundary patterns in React for handling different types of errors

Error handling is an essential aspect of developing robust applications in React. With the introduction of error boundaries in React 16, developers can now catch and handle errors that occur during rendering, lifecycle methods, or even in event handlers. In this blog post, we will explore different error boundary patterns to handle various types of errors effectively.

What are Error Boundaries?

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 entire application. They are implemented using a special componentDidCatch(error, info) lifecycle method.

Standard Error Boundary

The most common error boundary pattern is to wrap a component with an error boundary component. This approach catches errors within the component or its children and displays a fallback UI. Here’s an example:

import React, { Component } from 'react';

class ErrorBoundary extends Component {
  state = {
    hasError: false,
    error: null,
    errorInfo: null,
  };

  componentDidCatch(error, errorInfo) {
    this.setState({
      hasError: true,
      error: error,
      errorInfo: errorInfo,
    });

    // Log error to an error tracking service
    // e.g. Sentry, Bugsnag, etc.
  }

  render() {
    if (this.state.hasError) {
      // Display fallback UI
      return (
        <div>
          <h2>Something went wrong.</h2>
          <p>{this.state.error && this.state.error.toString()}</p>
        </div>
      );
    }

    // Render the component tree as usual
    return this.props.children;
  }
}

export default ErrorBoundary;

To use the error boundary, wrap any component that might throw an error with the ErrorBoundary component:

<ErrorBoundary>
  <MyComponent />
</ErrorBoundary>

Error Boundaries with Error Types

In some cases, you may want to handle specific error types differently. For example, you might want to display a custom error message for network errors or redirect to a specific page for authorization errors. Here’s an example of handling different error types with an error boundary:

class ErrorBoundary extends Component {
  state = {
    hasError: false,
    error: null,
    errorInfo: null,
  };

  componentDidCatch(error, errorInfo) {
    if (error instanceof NetworkError) {
      // Handle network errors
      this.setState({
        hasError: true,
        error: error,
        errorInfo: errorInfo,
      });
    } else if (error instanceof AuthorizationError) {
      // Handle authorization errors
      this.setState({
        hasError: true,
        error: error,
        errorInfo: errorInfo,
      });
    } else {
      // Log other errors to error tracking service
      // e.g. Sentry, Bugsnag, etc.
      this.setState({
        hasError: true,
        error: error,
        errorInfo: errorInfo,
      });
    }
  }

  // ...render method and fallback UI
}

export default ErrorBoundary;

Multiple Error Boundaries

In complex UIs, you might have multiple error boundaries to handle errors in different parts of the component tree independently. This approach provides more granular control over error handling. Here’s an example:

class ParentErrorBoundary extends Component {
  // ...

  render() {
    // Render child components
    return (
      <div>
        <h1>Parent Component</h1>
        <ErrorBoundary>
          <ChildComponent1 />
        </ErrorBoundary>
        <ErrorBoundary>
          <ChildComponent2 />
        </ErrorBoundary>
      </div>
    );
  }
}

export default ParentErrorBoundary;

By using multiple error boundaries, errors thrown in ChildComponent1 won’t be caught by ChildComponent2 and vice versa.

Conclusion

Error boundary patterns in React provide a powerful tool to handle errors gracefully and prevent application crashes. By implementing error boundaries, you can catch and manage errors in different parts of your component tree, display fallback UIs, and even handle specific error types differently. Understanding these patterns and incorporating them into your React applications will greatly improve the overall stability and user experience. #React #ErrorHandling