ErrorBoundary
The ErrorBoundary component can be used to catch run-time errors in the app by
displaying fallback content when an error is thrown. The ErrorBoundary
is a
minimal fork of the
react-error-boundary
package that only includes things I consider useful. Use the
react-error-boundary
if more complex behavior is required.
Simple Example
The ErrorBoundary
is a client component and requires fallback
(any ReactNode
) content to be
displayed.
The example below shows how the error boundary can catch run-time errors and display the fallback content without crashing the entire app. The demo must be reset to try again.
"use client";
import { Button } from "@react-md/core/button/Button";
import { ErrorBoundary } from "@react-md/core/error-boundary/ErrorBoundary";
import { useToggle } from "@react-md/core/useToggle";
import { type ReactElement } from "react";
export default function SimpleExample(): ReactElement {
return (
<ErrorBoundary fallback={<span>Fallback!</span>}>
<ErrorAfterClick />
</ErrorBoundary>
);
}
function ErrorAfterClick(): ReactElement {
const { toggle, toggled } = useToggle();
if (toggled) {
throw new Error("Unable to render");
}
return (
<Button onClick={toggle} theme="error" themeType="contained">
Cause Error
</Button>
);
}
Resettable Example
To help with cases where the app can be recovered after an error, the
ErrorBoundary
can also be reset using the useErrorBoundary
hook in the
fallback
content. The hook returns an object with:
error
- theError
ornull
errored
- boolean if there is an errorreset
- a function to reset the error boundary
The errored
flag should always be true
when this hook is called
from the fallback
component and will assert the error
is an Error
.
"use client";
import { Button } from "@react-md/core/button/Button";
import { ErrorBoundary } from "@react-md/core/error-boundary/ErrorBoundary";
import { useErrorBoundary } from "@react-md/core/error-boundary/useErrorBoundary";
import { Typography } from "@react-md/core/typography/Typography";
import { useToggle } from "@react-md/core/useToggle";
import { type ReactElement } from "react";
export default function ResettableExample(): ReactElement {
return (
<ErrorBoundary fallback={<ResettableFallback />}>
<ErrorAfterClick />
</ErrorBoundary>
);
}
function ErrorAfterClick(): ReactElement {
const { toggle, toggled } = useToggle();
if (toggled) {
throw new Error("Unable to render");
}
return (
<Button onClick={toggle} theme="error" themeType="contained">
Cause Error
</Button>
);
}
// it isn't shown by default since the error/stacktrace isn't quite useful in these runnable demos
const SHOW_ERROR_MESSAGE = false;
function ResettableFallback(): ReactElement | null {
const { error, errored, reset } = useErrorBoundary();
if (!errored) {
// this isn't possible from this flow as the `ResettableFallback` will
// only be mounted once there is an error
return null;
}
return (
<>
<Typography textColor="error">There was an error!</Typography>
{SHOW_ERROR_MESSAGE && (
<pre className="language-sh code-block code-block__pre">
<code className="language-sh">{error.stack ?? error.message}</code>
</pre>
)}
<Button onClick={reset}>Try Again</Button>
</>
);
}