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- theErrorornullerrored- 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>
</>
);
}