Centralized Error Handling in React with Error Boundaries and Context API

In React, managing errors gracefully is a crucial part of building a robust application. One effective way to handle errors is through the use of Error Boundaries and the Context API. This approach helps centralize error handling, making your code cleaner and easier to maintain. In this article, we will explore how to implement Error Boundaries, use them with Context API, and handle custom errors in a real-world example.

What is an Error Boundary?

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

Implementing an Error Boundary

To create an Error Boundary, you need to create a class component that implements either or both of the following lifecycle methods:

  • static getDerivedStateFromError(error)
  • componentDidCatch(error, errorInfo)

Here’s an example of an Error Boundary component:

import React, { Component } from 'react';

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

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

componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error("ErrorBoundary caught an error", error, errorInfo);
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return

Something went wrong.

;
}

return this.props.children;
}
}

export default ErrorBoundary;

Using Error Boundaries with Context API

To provide centralized error handling, we can use the Context API to manage error states and propagate them through the component tree.

First, create a context for error management:

import React, { createContext, useContext, useState } from 'react';

const ErrorContext = createContext();

export const useError = () => useContext(ErrorContext);

export const ErrorProvider = ({ children }) => {
const [error, setError] = useState(null);

const throwError = (error) => setError(error);

return (

{children}

);
};

Real-World Example with Custom Errors

Here’s how you can integrate the Error Boundary and Context API to handle custom errors in a real-world scenario:

  1. Set up the Error Provider:
    • import React from 'react';
      import ReactDOM from 'react-dom';
      import App from './App';
      import { ErrorProvider } from './ErrorContext';
      import ErrorBoundary from './ErrorBoundary';

      ReactDOM.render(




      ,
      document.getElementById('root')
      );

  2. Using the Error Context:
    • import React from 'react';
      import { useError } from './ErrorContext';

      const FaultyComponent = () => {
      const { throwError } = useError();

      const handleClick = () => {
      try {
      // Simulating a fault
      throw new Error('This is a custom error!');
      } catch (error) {
      throwError(error);
      }
      };

      return (

      );
      };

      export default FaultyComponent;

  3. Displaying Errors:
    • import React from 'react';
      import { useError } from './ErrorContext';

      const ErrorDisplay = () => {
      const { error } = useError();

      if (!error) return null;

      return (

      Error Occurred:

      {error.message}

      );
      };

      export default ErrorDisplay;

  4. App Component:
    • import React from 'react';
      import FaultyComponent from './FaultyComponent';
      import ErrorDisplay from './ErrorDisplay';

      const App = () => {
      return (

      My React App


      );
      };

      export default App;

By using Error Boundaries in conjunction with the Context API, you can create a centralized error handling system in your React application. This approach not only helps in catching and managing errors effectively but also ensures that your application remains user-friendly even when unexpected issues arise. By handling custom errors, you can provide more detailed and user-specific error messages, further improving the user experience.