SoFunction
Updated on 2025-04-14

How to implement React encapsulate custom Hook to capture all errors

How to catch errors in React

Error Boundaries

Error boundariesIt is a feature introduced in React 16 to capture JavaScript errors that occur in its child component tree, log errors and display alternate UI instead of the entire component tree crash.

Characteristics of error boundaries:

  • Only implemented through class components.
  • Capture errors in rendering processes, lifecycle methods, and constructors.
  • Errors in the event handler or errors in asynchronous code are not captured.

Global Error Listeners

To catch errors that are not caught by error boundaries, such as errors in event processors or errors in asynchronous code, we can use global error listeners, such asand

Encapsulation custom Hook captures all errors

To uniformly manage and catch all errors in React applications (including synchronization and asynchronous), we can encapsulate a custom Hook. The Hook will combine error boundaries and global error listening to achieve comprehensive error capture.

Step Overview

  • Create an error context (Error Context), used to pass error messages in the application.
  • Create an error provider component (ErrorProvider), set the error handling logic and provide the error status to the application.
  • Create a custom Hook (useError), used to trigger error reports in any component.
  • Create an error boundary component (ErrorBoundary), catch errors in component tree and pass through context.
  • Use ErrorProvider and ErrorBoundary in the application root component, ensure that the entire application can catch errors.

Implement code

1. Create an ErrorContext

import React from 'react';

const ErrorContext = ({
  error: null,
  setError: () => {},
});

export default ErrorContext;

2. Create an ErrorProvider component

import React, { useState, useEffect } from 'react';
import ErrorContext from '../context/ErrorContext';

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

  useEffect(() => {
    // Listen to global errors    const handleError = (event) => {
      setError( ||  || );
    };

    ('error', handleError);
    ('unhandledrejection', handleError);

    return () => {
      ('error', handleError);
      ('unhandledrejection', handleError);
    };
  }, []);

  return (
    < value={{ error, setError }}>
      {children}
    </>
  );
}

export default ErrorProvider;

3. Create a useError Hook

import { useContext } from 'react';
import ErrorContext from '../context/ErrorContext';

function useError() {
  const { setError } = useContext(ErrorContext);

  const reportError = (error) => {
    setError(error);
    ('Captured error:', error);
  };

  return reportError;
}

export default useError;

4. Create an ErrorBoundary component

import React from 'react';
import ErrorContext from '../context/ErrorContext';

class ErrorBoundary extends  {
  static contextType = ErrorContext;

  constructor(props) {
    super(props);
     = { hasError: false };
  }

  componentDidCatch(error, info) {
    ({ hasError: true });
    if ( && ) {
      (error);
    }
    ('ErrorBoundary caught an error:', error, info);
  }

  render() {
    if () {
      return <h1>An error occurred。</h1>;
    }

    return ;
  }
}

export default ErrorBoundary;

5. Use custom Hooks and ErrorBoundary

import React from 'react';
import ErrorProvider from './providers/ErrorProvider';
import ErrorBoundary from './components/ErrorBoundary';
import ExampleComponent from './components/ExampleComponent';
import ErrorDisplay from './components/ErrorDisplay';

function App() {
  return (
    <ErrorProvider>
      <ErrorBoundary>
        <ExampleComponent />
      </ErrorBoundary>
      <ErrorDisplay />
    </ErrorProvider>
  );
}

export default App;

Detailed code explanation

The implementation details of the above code will be explained step by step.

1.

Defines an error context for passing error states in the component tree.

import React from 'react';

const ErrorContext = ({
  error: null,
  setError: () => {},
});

export default ErrorContext;
  • useCreate a context with the initial value containingerrorandsetErrormethod.
  • The context allows access and updates to error status anywhere in the component tree.

2.

Create an error provider component, set up global error listening, and provide an error status.

import React, { useState, useEffect } from 'react';
import ErrorContext from '../context/ErrorContext';

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

  useEffect(() =&gt; {
    // Listen to global errors    const handleError = (event) =&gt; {
      setError( ||  || );
    };

    ('error', handleError);
    ('unhandledrejection', handleError);

    return () =&gt; {
      ('error', handleError);
      ('unhandledrejection', handleError);
    };
  }, []);

  return (
    &lt; value={{ error, setError }}&gt;
      {children}
    &lt;/&gt;
  );
}

export default ErrorProvider;
  • useuseStatemanageerrorstate.
  • useuseEffectAdd a global error listener:
    • Catch synchronization errors.
    • Catch unhandled Promise errors.
  • Remove the listener when component is uninstalled to avoid memory leaks.
  • useWillerrorandsetErrorProvided to subcomponents.

3.

Create a custom Hook for reporting errors in the component.

import { useContext } from 'react';
import ErrorContext from '../context/ErrorContext';

function useError() {
  const { setError } = useContext(ErrorContext);

  const reportError = (error) => {
    setError(error);
    ('Captured error:', error);
  };

  return reportError;
}

export default useError;
  • useuseContextGetsetErrormethod.
  • definitionreportErrorFunction for manually reporting errors.
  • While reporting an error, output the error message to the console.

4.

Creates a class component error boundary to capture errors that occur during rendering.

import React from 'react';
import ErrorContext from '../context/ErrorContext';

class ErrorBoundary extends  {
  static contextType = ErrorContext;

  constructor(props) {
    super(props);
     = { hasError: false };
  }

  componentDidCatch(error, info) {
    ({ hasError: true });
    if ( &amp;&amp; ) {
      (error);
    }
    ('ErrorBoundary caught an error:', error, info);
  }

  render() {
    if () {
      return &lt;h1&gt;An error occurred。&lt;/h1&gt;;
    }

    return ;
  }
}

export default ErrorBoundary;
  • Inherited from, implement error boundaries.
  • usestatic contextTypeGet the context.
  • existcomponentDidCatchIn the method:
    • Update local statushasError
    • Through contextsetErrorMethod reports an error.
    • Output the error message to the console.
  • If an error occurs, render the backup UI.

5.

Use in the root component of the applicationErrorProviderandErrorBoundary, ensure that the entire application can catch errors.

import React from 'react';
import ErrorProvider from './providers/ErrorProvider';
import ErrorBoundary from './components/ErrorBoundary';
import ExampleComponent from './components/ExampleComponent';
import ErrorDisplay from './components/ErrorDisplay';

function App() {
  return (
    <ErrorProvider>
      <ErrorBoundary>
        <ExampleComponent />
      </ErrorBoundary>
      <ErrorDisplay />
    </ErrorProvider>
  );
}

export default App;
  • ErrorProviderPackage the entire application and provide error status.
  • ErrorBoundaryPackage specific business components, such asExampleComponent
  • ErrorDisplayComponents are used to display error messages.

6.

An example component for triggering synchronous and asynchronous errors, testing the error capture mechanism.

import React from 'react';
import useError from '../hooks/useError';

function ExampleComponent() {
  const reportError = useError();

  const handleSyncError = () =&gt; {
    throw new Error('Synchronous Error Example');
  };

  const handleAsyncError = async () =&gt; {
    try {
      await (new Error('Async Error Example'));
    } catch (error) {
      reportError(error);
    }
  };

  return (
    &lt;div&gt;
      &lt;h2&gt;Sample Components&lt;/h2&gt;
      &lt;button onClick={handleSyncError}&gt;Trigger synchronization error&lt;/button&gt;
      &lt;button onClick={handleAsyncError}&gt;Trigger an asynchronous error&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default ExampleComponent;
  • Two buttons are provided to trigger synchronization and asynchronous errors respectively.
  • Synchronization error is thrown directlyErroraccomplish.
  • Asynchronous error is returned by returning a rejected Promise and incatchUsed inreportErrorReport an error.

7.

A component that displays the currently captured error message.

import React, { useContext } from 'react';
import ErrorContext from '../context/ErrorContext';

function ErrorDisplay() {
  const { error } = useContext(ErrorContext);

  if (!error) return null;

  return (
    &lt;div style={{ background: 'red', color: 'white', padding: '10px' }}&gt;
      &lt;h3&gt;Global Error Catch:&lt;/h3&gt;
      &lt;p&gt;{()}&lt;/p&gt;
    &lt;/div&gt;
  );
}

export default ErrorDisplay;
  • useuseContextGet the current error status.
  • If there is an error, render the error message.

Summarize

This article details a variety of ways to catch errors in React, including error boundaries and global error listening, and shows how to encapsulate a custom Hook to manage and capture all synchronous and asynchronous errors. This centralized error handling mechanism helps improve the stability and maintenance of the application, allowing developers to more conveniently monitor and handle errors and improve user experience.

Through the above implementation, developers can easily catch and handle various errors in React applications, whether they occur during rendering, in lifecycle methods, or in asynchronous operations. This provides strong support for building robust and reliable React applications.

The above is the detailed content of the implementation method of React encapsulation custom Hook to capture all errors. For more information about React Hook to capture all errors, please follow my other related articles!