React Logoreact-error-boundary

Error Boundaries are a React 16+ feature that allows components to catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the crashed component tree. They catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

The `react-error-boundary` library is a popular and convenient wrapper around React's native Error Boundary functionality, simplifying its usage, especially for functional components. While native Error Boundaries require a class component with `static getDerivedStateFromError()` and `componentDidCatch()`, `react-error-boundary` provides a simple `ErrorBoundary` component that can be used directly with props to define the fallback UI, handle error logging, and reset functionality.

Key features and how it works:

1. Simplified API: Instead of writing a class component, you can use the `ErrorBoundary` component provided by the library directly in your JSX.
2. Fallback UI: You can define what to render when an error occurs using various props:
* `fallback`: A simple React element to render.
* `FallbackComponent`: A component to render, receiving `error` and `resetErrorBoundary` props.
* `fallbackRender`: A function that receives an object `{ error, resetErrorBoundary }` and returns a React element.
3. Error Logging (`onError`): The `onError` prop is a function that gets called when an error is caught. It receives the `error` object and an `info` object (containing `componentStack`), allowing you to log the error to an external service (e.g., Sentry, Bugsnag).
4. Reset Functionality (`onReset`, `resetKeys`): Often, after an error, you might want to give the user an option to "try again" by resetting the state that caused the error. The `FallbackComponent` or `fallbackRender` receives a `resetErrorBoundary` function which, when called, will clear the error state and re-render the children. The `onReset` prop is a callback that gets fired when `resetErrorBoundary` is called. The `resetKeys` prop (an array of dependencies) can be used to automatically reset the error boundary if any of its values change, which is useful for situations like navigating to a different route.
5. Hooks API: The library also provides a `useErrorBoundary` hook for more fine-grained control within child components to programmatically show or hide errors.

When to use `react-error-boundary`:

* Preventing entire application crashes due to errors in a specific part of the UI.
* Displaying user-friendly messages instead of blank screens or cryptic error messages.
* Logging client-side errors to a central monitoring system.
* Providing a "try again" button to recover from transient errors.

Limitations (same as native React Error Boundaries):

* They only catch errors in the render phase, lifecycle methods, and constructors of their children. They do not catch errors in:
* Event handlers (e.g., `onClick`, `onChange`). You must handle these errors manually with `try-catch`.
* Asynchronous code (`setTimeout`, `requestAnimationFrame`, `Promise.then/catch`).
* Server-side rendering.
* Errors thrown in the error boundary itself (to prevent infinite loops).

By encapsulating potentially error-prone parts of your application with `react-error-boundary`, you can make your application more robust and provide a better user experience.

Example Code

import React, { useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

// 1. A Fallback Component to display when an error occurs
function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert" style={{ border: '1px solid red', padding: '10px', margin: '10px', backgroundColor: '#ffe6e6' }}>
      <p><strong>Something went wrong:</strong></p>
      <pre style={{ color: 'darkred' }}>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
      <p>This part of the UI crashed. The rest of the app should still work.</p>
    </div>
  );
}

// 2. A component that is designed to throw an error under certain conditions
function BuggyCounter() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    if (count === 5) {
      // Simulate a runtime error during rendering
      throw new Error("I crashed because count reached 5!");
    }
    setCount(c => c + 1);
  };

  return (
    <div style={{ border: '1px solid #ccc', padding: '10px', margin: '10px' }}>
      <h2>Buggy Counter</h2>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
      <p>Click until count is 5 to see the error boundary in action.</p>
    </div>
  );
}

// 3. The main App component using ErrorBoundary
function App() {
  const handleReset = () => {
    // This function is called when resetErrorBoundary is triggered from the FallbackComponent.
    // Here you might clear some global state, navigate away, etc.
    console.log("ErrorBoundary was reset! Application state might need to be reset too.");
  };

  const handleError = (error, info) => {
    // This function is called when an error is caught.
    // You would typically log this to an error monitoring service (e.g., Sentry, Bugsnag).
    console.error("Caught an error in ErrorBoundary:", error, info);
  };

  return (
    <div style={{ fontFamily: 'Arial, sans-serif', padding: '20px' }}>
      <h1>`react-error-boundary` Example</h1>

      <p>This is content outside the error boundary. It should always render.</p>

      <ErrorBoundary
        FallbackComponent={ErrorFallback} // Use our custom fallback component
        onReset={handleReset}           // Callback when resetErrorBoundary is called
        onError={handleError}           // Callback when an error is caught
      >
        {/* Children components that might throw errors are placed here */}
        <BuggyCounter />
      </ErrorBoundary>

      <hr />

      <p>This part of the application is rendered after the ErrorBoundary and remains unaffected by errors within it.</p>

      <ErrorBoundary
        fallback={<p style={{ color: 'blue' }}>A simpler fallback message!</p>}
      >
        <h2>Another Buggy Counter (with simple fallback)</h2>
        <BuggyCounter />
      </ErrorBoundary>
    </div>
  );
}

export default App;