Error Boundaries
StateMesh provides MeshErrorBoundary and MeshErrorResetBoundary for handling errors from Suspense resource reads, transaction failures, and other async operations.
MeshErrorBoundary
Wrap components that may throw (e.g., Suspense resource reads):
import { Suspense } from "react";
import { MeshErrorBoundary, useSuspenseMeshResource } from "statemesh-core";
function Products() {
const products = useSuspenseMeshResource(productsResource, filters);
return products.data.map((p) => <div key={p.id}>{p.name}</div>);
}
function ProductsRoute() {
return (
<MeshErrorBoundary
fallbackRender={({ error, reset }) => (
<div>
<p>Error: {error.message}</p>
<button onClick={reset}>Retry</button>
</div>
)}
>
<Suspense fallback={<p>Loading...</p>}>
<Products />
</Suspense>
</MeshErrorBoundary>
);
}Props
| Prop | Type | Description |
|---|---|---|
fallback | ReactNode | Static fallback UI |
fallbackRender | ({ error, reset }) => ReactNode | Dynamic fallback with error and reset |
onError | (error, info) => void | Called when an error is caught |
Reset Boundary
Use MeshErrorResetBoundary to control when the error boundary resets:
import { MeshErrorResetBoundary, useMeshErrorResetBoundary } from "statemesh-core";
function ResettableSection() {
const { reset } = useMeshErrorResetBoundary();
return (
<MeshErrorResetBoundary>
<MeshErrorBoundary fallbackRender={({ error }) => (
<div>
<p>{error.message}</p>
<button onClick={reset}>Try again</button>
</div>
)}>
<Suspense fallback={<p>Loading...</p>}>
<AsyncComponent />
</Suspense>
</MeshErrorBoundary>
</MeshErrorResetBoundary>
);
}useMeshErrorResetBoundary
const { reset } = useMeshErrorResetBoundary();Call reset() to clear the error state and re-render the children. This forces the Suspense boundary to retry the async operation.
Pattern: Route Error Boundary
function RouteErrorBoundary({ children }: { children: React.ReactNode }) {
return (
<MeshErrorBoundary
fallbackRender={({ error, reset }) => (
<div className="error-page">
<h1>Something went wrong</h1>
<p>{error.message}</p>
<button onClick={reset}>Try again</button>
<button onClick={() => window.location.href = "/"}>Go home</button>
</div>
)}
onError={(error) => {
console.error("Route error:", error);
analytics.track("error", { message: error.message });
}}
>
{children}
</MeshErrorBoundary>
);
}Pattern: Section Error Boundary
function ProductSection() {
return (
<MeshErrorBoundary
fallbackRender={({ error, reset }) => (
<div className="section-error">
<p>Failed to load products: {error.message}</p>
<button onClick={reset}>Retry</button>
</div>
)}
>
<Suspense fallback={<ProductSkeleton />}>
<ProductList />
</Suspense>
</MeshErrorBoundary>
);
}Important Notes
TIP
MeshErrorBoundary catches errors from useSuspenseMeshResource, transaction failures thrown during render, and any other errors thrown in child components.
WARNING
The reset callback forces a re-render of the children. If the underlying error persists (e.g., the API is still down), the error boundary will catch the new error and show the fallback again.
TIP
Use multiple nested error boundaries for granular error handling. A product card can fail independently without taking down the entire page.
