ErrorBoundary
A utility component for gracefully handling errors in React component trees.
Overview
Taken from react-error-boundary, with modifications to support both React nodes and render functions for error states, automatic reset via keys, and imperative reset via API.
Key Features
- Error Isolation - Contains errors within a boundary to prevent full application crashes
- Flexible Fallbacks - Supports both React nodes and render functions for error states
- Reset Keys - Automatically resets when specified dependencies change
- Imperative Reset - Allows manual error recovery via
resetErrorBoundary - Context Integration - Exposes error state and reset functions to child components
- TypeScript Support - Full type safety for errors and props
Basic Usage
import { ErrorBoundary } from "@zayne-labs/ui-react/common/error-boundary";
export default function App() {
return (
<ErrorBoundary
fallback={<div>Something went wrong. Please try again.</div>}
onError={(error) => console.error("Caught an error:", error)}
>
<ComponentThatMightThrow />
</ErrorBoundary>
);
}Custom Error Fallback
You can provide a function component that receives error details and a reset function:
import { ErrorBoundary } from "@zayne-labs/ui-react/common";
export default function App() {
return (
<ErrorBoundary
fallback={({ error, resetErrorBoundary }) => (
<div>
<h2>An error occurred</h2>
<p>{error.message}</p>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
)}
>
<ComponentThatMightThrow />
</ErrorBoundary>
);
}Reset Keys
The resetKeys prop allows you to automatically reset the error boundary when certain values change:
import { ErrorBoundary } from "@zayne-labs/ui-react/common";
import { useState } from "react";
export default function App() {
const [counter, setCounter] = useState(0);
return (
<div>
<button onClick={() => setCounter((c) => c + 1)}>Increment Counter: {counter}</button>
<ErrorBoundary
fallback={<div>Error occurred! Increment the counter to try again.</div>}
resetKeys={[counter]}
onReset={({ reason }) => console.log(`Error boundary reset due to: ${reason}`)}
>
<ComponentThatThrowsWhenCounterIsEven counter={counter} />
</ErrorBoundary>
</div>
);
}
function ComponentThatThrowsWhenCounterIsEven({ counter }) {
if (counter % 2 === 0 && counter !== 0) {
throw new Error(`Counter is even: ${counter}`);
}
return <div>Counter is {counter}</div>;
}Using the Hook API
The useErrorBoundary hook allows you to programmatically trigger and handle errors:
import { ErrorBoundary, useErrorBoundary } from "@zayne-labs/ui-react/common";
export default function App() {
return (
<ErrorBoundary
fallback={({ resetErrorBoundary }) => (
<div>
<p>Failed to fetch data</p>
<button onClick={resetErrorBoundary}>Retry</button>
</div>
)}
>
<DataFetcher />
</ErrorBoundary>
);
}
function DataFetcher() {
const { showBoundary } = useErrorBoundary();
React.useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("/api/data");
return await response.json();
} catch (error) {
showBoundary(error);
}
};
fetchData();
}, [showBoundary]);
return <div>Loading data...</div>;
}Nested Error Boundaries
You can nest error boundaries to provide different fallback UIs for different parts of your app:
import { ErrorBoundary } from "@zayne-labs/ui-react/common";
export default function App() {
return (
<ErrorBoundary fallback={<div>Application error</div>}>
<Header />
<main>
<ErrorBoundary fallback={<div>Content error. Other parts still work.</div>}>
<MainContent />
</ErrorBoundary>
</main>
<ErrorBoundary fallback={<div>Footer error. Other parts still work.</div>}>
<Footer />
</ErrorBoundary>
</ErrorBoundary>
);
}TypeScript Support
The ErrorBoundary component provides full type safety:
import { ErrorBoundary } from "@zayne-labs/ui-react/common";
interface ApiError extends Error {
endpoint: string;
statusCode: number;
}
export default function App() {
return (
<ErrorBoundary
fallback={({
error,
resetErrorBoundary,
}: {
error: ApiError;
resetErrorBoundary: () => void;
}) => (
<div>
<h2>API Error</h2>
<p>Status: {error.statusCode}</p>
<p>Endpoint: {error.endpoint}</p>
<p>Message: {error.message}</p>
<button onClick={resetErrorBoundary}>Retry</button>
</div>
)}
>
<ApiComponent />
</ErrorBoundary>
);
}API Reference
ErrorBoundary Component
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | Required | The components that might throw errors |
fallback | React.ReactNode | ((props: FallbackProps) => React.ReactNode) | undefined | The UI to display when an error occurs |
onError | (error: Error, info: React.ErrorInfo & { ownerStack?: string }) => void | undefined | Called when an error is caught |
onReset | (details: { next?: unknown[]; prev?: unknown[]; reason: "keys" } | { parameters: unknown[]; reason: "imperative-api" }) => void | undefined | Called when the error boundary is reset |
resetKeys | unknown[] | undefined | Array of values that will trigger boundary reset when changed |
FallbackProps
Props passed to the fallback function:
| Prop | Type | Description |
|---|---|---|
error | unknown | The error that was caught |
resetErrorBoundary | (...args: unknown[]) => void | Function to reset the error boundary |
useErrorBoundary Hook
import { useErrorBoundary } from "@zayne-labs/ui-react/common/error-boundary";
export default function App() {
const { resetBoundary, showBoundary } = useErrorBoundary();
return (
<div>
<button onClick={() => showBoundary(new Error("Something went wrong"))}>Trigger Error</button>
<button onClick={resetBoundary}>Reset Error Boundary</button>
</div>
);
}| Return Value | Type | Description |
|---|---|---|
resetBoundary | () => void | Function to reset the error boundary |
showBoundary | (error: TError) => void | Function to manually trigger the error boundary with a specific error |
ErrorBoundaryContext
Values available through the ErrorBoundaryContext:
| Value | Type | Description |
|---|---|---|
error | unknown | Current error (if any) |
hasError | boolean | Whether an error is currently active |
resetErrorBoundary | (...args: unknown[]) => void | Function to reset the error boundary |
Best Practices
- Strategic Placement - Place error boundaries strategically around critical UI sections
- Multiple Boundaries - Use multiple, nested boundaries for better isolation
- Telemetry Integration - Connect the
onErrorhandler to your error monitoring service - Clear Error Messages - Provide clear, user-friendly error messages and recovery options
- Testing - Explicitly test error scenarios with your error boundaries
Accessibility Considerations
When implementing error states:
- Focus Management - Set focus to the error message or primary action button
- Descriptive Errors - Make error messages descriptive and actionable
- ARIA Attributes - Use
role="alert"oraria-livefor dynamic error messages - Color Contrast - Ensure error states have sufficient color contrast
Summary
The ErrorBoundary component provides a comprehensive solution for error handling in React applications. By isolating errors, providing fallback UIs, and offering reset capabilities, it enables you to build more resilient applications with better user experiences during failure scenarios.