Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/pending-changes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@ jobs:
- uses: pnpm/action-setup@v2
with:
version: 10

- name: Install dependencies
run: pnpm install --frozen-lockfile --recursive
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true'

- name: Setup Google Chrome
uses: browser-actions/setup-chrome@v2
id: setup-chrome
with:
install-dependencies: true

- uses: nickcharlton/diff-check@main
with:
command: pnpm run compile
command: pnpm dev & pnpm run compile
env:
CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }}
119 changes: 112 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,97 @@ yarn add react-error-boundary

Frequently asked questions can be found [here](https://react-error-boundary-lib.vercel.app/common-questions).

## Quick start

Wrap an `ErrorBoundary` around the part of the tree where you want to show a fallback UI if rendering fails:

```tsx
"use client";

import { ErrorBoundary, getErrorMessage } from "react-error-boundary";

function ErrorFallback({
error,
resetErrorBoundary,
}: {
error: unknown;
resetErrorBoundary: () => void;
}) {
return (
<div role="alert">
<p>Something went wrong:</p>
<pre>{getErrorMessage(error)}</pre>
<button onClick={resetErrorBoundary}>Try again</button>
</div>
);
}

export default function App() {
return (
<ErrorBoundary
fallbackRender={({ error, resetErrorBoundary }) => (
<ErrorFallback error={error} resetErrorBoundary={resetErrorBoundary} />
)}
onError={(error, info) => {
// Log the error to your error reporting service
}}
>
{/* Render your app here */}
</ErrorBoundary>
);
}
```

## What errors are caught?

This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary), so it has all of the advantages and constraints of that API.

Error boundaries catch errors thrown while rendering the tree below them.

Error boundaries do not catch errors thrown during:

- Server side rendering
- Event handlers
- Errors thrown in the error boundary itself
- Async code that runs after rendering, like `setTimeout` callbacks or unresolved promises

React 19 includes one important async exception: errors thrown inside Actions, including functions passed to the `startTransition` function returned by `useTransition`, can be caught by the nearest error boundary.

For user-initiated async work, wrap the work in a Transition so React can catch errors from the Action and show the nearest error boundary:

```tsx
"use client";

import { useTransition } from "react";
import { ErrorBoundary } from "react-error-boundary";

function UserProfileContainer({ username }: { username: string }) {
return (
<ErrorBoundary fallback={<p>Could not load profile</p>}>
<UserProfile username={username} />
</ErrorBoundary>
);
}

function UserProfile({ username }: { username: string }) {
const [isPending, startTransition] = useTransition();

function loadProfile() {
startTransition(async () => {
await fetchUserProfile(username);
});
}

return (
<button disabled={isPending} onClick={loadProfile}>
{isPending ? "Loading..." : "Load profile"}
</button>
);
}
```

For async work outside of Actions, catch the error yourself and pass it to the nearest boundary with `useErrorBoundary`.

## API

### ErrorBoundary
Expand All @@ -33,16 +124,26 @@ A reusable React [error boundary](https://react.dev/reference/react/Component#ca
Wrap this component around other React components to "catch" errors and render a fallback UI.

This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),
so it has all of the advantages and constraints of that API.
This means that it can't catch errors during:
- Server side rendering</li>
so it has all of the advantages and constraints of that API. Error boundaries catch errors thrown while rendering
the tree below them.

Error boundaries do not catch errors thrown during:
- Server side rendering
- Event handlers
- Asynchronous code (including effects)
- Errors thrown in the error boundary itself
- Async code that runs after rendering, like `setTimeout` callbacks or unresolved promises

React 19 includes one important async exception: errors thrown inside Actions, including functions passed to the
`startTransition` function returned by `useTransition`, can be caught by the nearest error boundary.

For user-initiated async work, wrap the work in a Transition so React can catch errors from the Action. The
`useErrorBoundary` hook can also be used to pass errors from async code outside of Actions to the nearest error
boundary.

ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.
Refer to the documentation to determine which is best for your application.

ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
ℹ️ This is a **client component**. You can only pass props to it that are serializable or use it in files that have a `"use client";` directive.
<!-- ErrorBoundary:description:end -->

#### Required props
Expand Down Expand Up @@ -72,14 +173,14 @@ None
</tr>
<tr>
<td>onReset</td>
<td><p>Optional callback to to be notified when an error boundary is &quot;reset&quot; so React can retry the failed render.</p>
<td><p>Optional callback to be notified when an error boundary is reset so React can retry the failed render.</p>
</td>
</tr>
<tr>
<td>resetKeys</td>
<td><p>When changed, these keys will reset a triggered error boundary.
This can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).
See the the documentation for examples of how to use this prop.</p>
See the documentation for examples of how to use this prop.</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -109,10 +210,13 @@ See the the documentation for examples of how to use this prop.</p>
<!-- ErrorBoundary:optional-props:end -->

# FAQ

## `ErrorBoundary` cannot be used as a JSX component

This error can be caused by a version mismatch between [react](https://npmjs.com/package/react) and [@types/react](https://npmjs.com/package/@types/react). To fix this, ensure that both match exactly, e.g.:

If using NPM:

```json
{
...
Expand All @@ -124,6 +228,7 @@ If using NPM:
```

If using Yarn:

```json
{
...
Expand Down
20 changes: 15 additions & 5 deletions lib/components/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,26 @@ const initialState: ErrorBoundaryState = {
* Wrap this component around other React components to "catch" errors and render a fallback UI.
*
* This package is built on top of React [error boundaries](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary),
* so it has all of the advantages and constraints of that API.
* This means that it can't catch errors during:
* - Server side rendering</li>
* so it has all of the advantages and constraints of that API. Error boundaries catch errors thrown while rendering
* the tree below them.
*
* Error boundaries do not catch errors thrown during:
* - Server side rendering
* - Event handlers
* - Asynchronous code (including effects)
* - Errors thrown in the error boundary itself
* - Async code that runs after rendering, like `setTimeout` callbacks or unresolved promises
*
* React 19 includes one important async exception: errors thrown inside Actions, including functions passed to the
* `startTransition` function returned by `useTransition`, can be caught by the nearest error boundary.
*
* For user-initiated async work, wrap the work in a Transition so React can catch errors from the Action. The
* `useErrorBoundary` hook can also be used to pass errors from async code outside of Actions to the nearest error
* boundary.
*
* ℹ️ The component provides several ways to render a fallback: `fallback`, `fallbackRender`, and `FallbackComponent`.
* Refer to the documentation to determine which is best for your application.
*
* ℹ️ This is a **client component**. You can only pass props to it that are serializeable or use it in files that have a `"use client";` directive.
* ℹ️ This is a **client component**. You can only pass props to it that are serializable or use it in files that have a `"use client";` directive.
*/
export class ErrorBoundary extends Component<
ErrorBoundaryProps,
Expand Down
6 changes: 3 additions & 3 deletions lib/hooks/useErrorBoundary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ export function useErrorBoundary(): {
/**
* Trigger the nearest error boundary to display the error provided.
*
* ℹ️ React only handles errors thrown during render or during component lifecycle methods (e.g. effects and did-mount/did-update).
* Errors thrown in event handlers, or after async code has run, will not be caught.
* This method is a way to imperatively trigger an error boundary during these phases.
* ℹ️ React handles errors thrown while rendering.
* Errors thrown in event handlers, or after async code has run, will not be caught automatically.
* This method is a way to imperatively show the nearest error boundary for those errors.
*/
showBoundary: (error: unknown) => void;
} {
Expand Down
4 changes: 2 additions & 2 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ErrorBoundarySharedProps = PropsWithChildren<{
onError?: (error: unknown, info: ErrorInfo) => void;

/**
* Optional callback to to be notified when an error boundary is "reset" so React can retry the failed render.
* Optional callback to be notified when an error boundary is reset so React can retry the failed render.
*/
onReset?: (
details:
Expand All @@ -37,7 +37,7 @@ type ErrorBoundarySharedProps = PropsWithChildren<{
/**
* When changed, these keys will reset a triggered error boundary.
* This can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).
* See the the documentation for examples of how to use this prop.
* See the documentation for examples of how to use this prop.
*/
resetKeys?: unknown[];
}>;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"react-docgen-typescript": "^2.4.0",
"react-dom": "^19.2.3",
"react-error-boundary": "^6.0.0",
"react-lib-tools": "0.0.47",
"react-lib-tools": "0.0.53",
"react-router-dom": "^7.6.3",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-visualizer": "^6.0.3",
Expand Down
17 changes: 5 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 13 additions & 4 deletions public/generated/docs/ErrorBoundary.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@
"content": "<p>A reusable React <a href=\"https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary\">error boundary</a> component.\nWrap this component around other React components to &quot;catch&quot; errors and render a fallback UI.</p>\n"
},
{
"content": "<p>This package is built on top of React <a href=\"https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary\">error boundaries</a>,\nso it has all of the advantages and constraints of that API.\nThis means that it can't catch errors during:</p>\n<ul>\n<li>Server side rendering&lt;/li&gt;</li>\n<li>Event handlers</li>\n<li>Asynchronous code (including effects)</li>\n</ul>\n"
"content": "<p>This package is built on top of React <a href=\"https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary\">error boundaries</a>,\nso it has all of the advantages and constraints of that API. Error boundaries catch errors thrown while rendering\nthe tree below them.</p>\n"
},
{
"content": "<p>Error boundaries do not catch errors thrown during:</p>\n<ul>\n<li>Server side rendering</li>\n<li>Event handlers</li>\n<li>Errors thrown in the error boundary itself</li>\n<li>Async code that runs after rendering, like <code>setTimeout</code> callbacks or unresolved promises</li>\n</ul>\n"
},
{
"content": "<p>React 19 includes one important async exception: errors thrown inside Actions, including functions passed to the\n<code>startTransition</code> function returned by <code>useTransition</code>, can be caught by the nearest error boundary.</p>\n"
},
{
"content": "<p>For user-initiated async work, wrap the work in a Transition so React can catch errors from the Action. The\n<code>useErrorBoundary</code> hook can also be used to pass errors from async code outside of Actions to the nearest error\nboundary.</p>\n"
},
{
"content": "<p>The component provides several ways to render a fallback: <code>fallback</code>, <code>fallbackRender</code>, and <code>FallbackComponent</code>.\nRefer to the documentation to determine which is best for your application.</p>\n",
"intent": "primary"
},
{
"content": "<p>This is a <strong>client component</strong>. You can only pass props to it that are serializeable or use it in files that have a <code>&quot;use client&quot;;</code> directive.</p>\n",
"content": "<p>This is a <strong>client component</strong>. You can only pass props to it that are serializable or use it in files that have a <code>&quot;use client&quot;;</code> directive.</p>\n",
"intent": "primary"
}
],
Expand All @@ -31,7 +40,7 @@
"onReset": {
"description": [
{
"content": "<p>Optional callback to to be notified when an error boundary is &quot;reset&quot; so React can retry the failed render.</p>\n"
"content": "<p>Optional callback to be notified when an error boundary is reset so React can retry the failed render.</p>\n"
}
],
"html": "<div><span class=\"tok-variableName\"><span class=\"tok-propertyName\">onReset</span></span><span class=\"tok-operator\">?</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">(</span><span class=\"tok-variableName tok-definition\">details</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">reason</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-string\">\"imperative-api\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">args</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">unknown</span><span class=\"tok-punctuation\">[</span><span class=\"tok-punctuation\">]</span><span class=\"tok-punctuation\">;</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"\"> </span><span class=\"tok-operator\">|</span><span class=\"\"> </span><span class=\"tok-punctuation\">{</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">reason</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-string\">\"keys\"</span><span class=\"tok-punctuation\">;</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">prev</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">unknown</span><span class=\"tok-punctuation\">[</span><span class=\"tok-punctuation\">]</span><span class=\"tok-punctuation\">;</span><span class=\"\"> </span><span class=\"tok-propertyName tok-definition\">next</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-typeName\">unknown</span><span class=\"tok-punctuation\">[</span><span class=\"tok-punctuation\">]</span><span class=\"tok-punctuation\">;</span><span class=\"\"> </span><span class=\"tok-punctuation\">}</span><span class=\"tok-punctuation\">)</span><span class=\"\"> </span><span class=\"tok-punctuation\">=&#62;</span><span class=\"\"> </span><span class=\"tok-keyword\">void</span></div>",
Expand All @@ -41,7 +50,7 @@
"resetKeys": {
"description": [
{
"content": "<p>When changed, these keys will reset a triggered error boundary.\nThis can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).\nSee the the documentation for examples of how to use this prop.</p>\n"
"content": "<p>When changed, these keys will reset a triggered error boundary.\nThis can be useful when an error condition may be tied to some specific state (that can be uniquely identified by key).\nSee the documentation for examples of how to use this prop.</p>\n"
}
],
"html": "<div><span class=\"tok-variableName\"><span class=\"tok-propertyName\">resetKeys</span></span><span class=\"tok-operator\">?</span><span class=\"tok-punctuation\">:</span><span class=\"\"> </span><span class=\"tok-variableName\">unknown</span><span class=\"tok-punctuation\">[</span><span class=\"tok-punctuation\">]</span></div>",
Expand Down
Loading
Loading