> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/preactjs/preact/llms.txt
> Use this file to discover all available pages before exploring further.

# useErrorBoundary

> Catches errors in child components and provides error handling

`useErrorBoundary` allows you to catch errors that occur in child components and handle them gracefully. It provides both the caught error and a function to reset the error state.

## Signature

```typescript theme={null}
function useErrorBoundary(
  callback?: (error: any, errorInfo: ErrorInfo) => Promise<void> | void
): [any, () => void]
```

## Parameters

<ParamField path="callback" type="(error: any, errorInfo: ErrorInfo) => Promise<void> | void" optional>
  An optional callback function that is invoked when an error is caught. Receives the error and additional error information (component stack trace). Can be used for error logging or reporting.
</ParamField>

## Returns

Returns a tuple containing:

1. **Error** (`any`): The caught error, or `undefined` if no error has occurred
2. **Reset function** (`() => void`): A function to clear the error state and attempt to re-render

## Basic Usage

```jsx theme={null}
import { useErrorBoundary } from 'preact/hooks';

function BuggyComponent() {
  throw new Error('Something went wrong!');
  return <div>This won't render</div>;
}

function App() {
  const [error, resetError] = useErrorBoundary();

  if (error) {
    return (
      <div>
        <h1>Error Occurred</h1>
        <p>{error.message}</p>
        <button onClick={resetError}>Try Again</button>
      </div>
    );
  }

  return <BuggyComponent />;
}
```

## With Error Logging

```jsx theme={null}
function App() {
  const [error, resetError] = useErrorBoundary((error, errorInfo) => {
    // Log error to an error reporting service
    console.error('Error caught:', error);
    console.error('Component stack:', errorInfo.componentStack);

    // Send to error tracking service
    logErrorToService({
      message: error.message,
      stack: error.stack,
      componentStack: errorInfo.componentStack
    });
  });

  if (error) {
    return (
      <div className="error-screen">
        <h1>Oops! Something went wrong</h1>
        <button onClick={resetError}>Reload</button>
      </div>
    );
  }

  return <MainApp />;
}
```

## Async Error Logging

```jsx theme={null}
function App() {
  const [error, resetError] = useErrorBoundary(async (error, errorInfo) => {
    try {
      await fetch('/api/log-error', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          error: error.message,
          stack: error.stack,
          componentStack: errorInfo.componentStack,
          timestamp: new Date().toISOString()
        })
      });
    } catch (logError) {
      console.error('Failed to log error:', logError);
    }
  });

  if (error) {
    return (
      <div>
        <h1>Error: {error.message}</h1>
        <button onClick={resetError}>Retry</button>
      </div>
    );
  }

  return <App />;
}
```

## Granular Error Boundaries

```jsx theme={null}
function UserProfile({ userId }) {
  const [error, resetError] = useErrorBoundary();

  if (error) {
    return (
      <div className="profile-error">
        <p>Failed to load profile</p>
        <button onClick={resetError}>Retry</button>
      </div>
    );
  }

  return <ProfileContent userId={userId} />;
}

function App() {
  return (
    <div>
      <Header />
      <UserProfile userId={123} />
      <UserProfile userId={456} />
      <Footer />
    </div>
  );
}
```

## With Fallback UI

```jsx theme={null}
function ErrorFallback({ error, resetError }) {
  return (
    <div className="error-container">
      <h2>Something went wrong</h2>
      <details>
        <summary>Error details</summary>
        <pre>{error.message}</pre>
        <pre>{error.stack}</pre>
      </details>
      <button onClick={resetError}>Try again</button>
    </div>
  );
}

function App() {
  const [error, resetError] = useErrorBoundary((error) => {
    console.error('Caught error:', error);
  });

  if (error) {
    return <ErrorFallback error={error} resetError={resetError} />;
  }

  return <MainContent />;
}
```

## Multiple Error Boundaries

```jsx theme={null}
function Section({ title, children }) {
  const [error, resetError] = useErrorBoundary();

  if (error) {
    return (
      <div className="section-error">
        <h3>{title} - Error</h3>
        <p>{error.message}</p>
        <button onClick={resetError}>Retry</button>
      </div>
    );
  }

  return (
    <section>
      <h3>{title}</h3>
      {children}
    </section>
  );
}

function App() {
  return (
    <div>
      <Section title="User Info">
        <UserInfo />
      </Section>
      <Section title="Recent Activity">
        <ActivityFeed />
      </Section>
      <Section title="Settings">
        <UserSettings />
      </Section>
    </div>
  );
}
```

## With State Reset

```jsx theme={null}
function DataList() {
  const [data, setData] = useState([]);
  const [error, resetError] = useErrorBoundary();

  const handleReset = () => {
    setData([]); // Reset component state
    resetError(); // Clear error state
  };

  if (error) {
    return (
      <div>
        <p>Failed to load data: {error.message}</p>
        <button onClick={handleReset}>Reset and Retry</button>
      </div>
    );
  }

  return (
    <ul>
      {data.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}
```

## Error Reporting Service

```jsx theme={null}
const errorReportingService = {
  report: async (error, errorInfo, context) => {
    await fetch('https://api.example.com/errors', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        message: error.message,
        stack: error.stack,
        componentStack: errorInfo.componentStack,
        userAgent: navigator.userAgent,
        url: window.location.href,
        context
      })
    });
  }
};

function App() {
  const [error, resetError] = useErrorBoundary((error, errorInfo) => {
    errorReportingService.report(error, errorInfo, {
      user: getCurrentUser(),
      timestamp: Date.now(),
      version: APP_VERSION
    });
  });

  if (error) {
    return (
      <div>
        <h1>Application Error</h1>
        <p>We've been notified and are working on a fix.</p>
        <button onClick={resetError}>Reload Application</button>
      </div>
    );
  }

  return <MainApp />;
}
```

## Conditional Error Display

```jsx theme={null}
function App() {
  const [error, resetError] = useErrorBoundary();
  const [showDetails, setShowDetails] = useState(false);

  if (error) {
    return (
      <div className="error-page">
        <h1>An error occurred</h1>
        <p>{error.message}</p>
        {showDetails && (
          <pre className="error-stack">{error.stack}</pre>
        )}
        <div className="error-actions">
          <button onClick={resetError}>Try Again</button>
          <button onClick={() => setShowDetails(!showDetails)}>
            {showDetails ? 'Hide' : 'Show'} Details
          </button>
        </div>
      </div>
    );
  }

  return <App />;
}
```

<Note>
  `useErrorBoundary` only catches errors in child components during rendering, in lifecycle methods, and in constructors. It does **not** catch errors in:

  * Event handlers (use try-catch for these)
  * Asynchronous code (setTimeout, promises)
  * Server-side rendering
  * Errors thrown in the error boundary itself
</Note>

<Note>
  The error boundary will catch errors from all descendant components. Place error boundaries strategically to provide appropriate fallback UIs at different levels of your component tree.
</Note>

<Note>
  Always call `resetError()` before attempting to re-render components that previously threw errors. This clears the error state and allows the error boundary to catch new errors.
</Note>
