Files
AI/ontology_platform/web/frontend/src/components/ErrorBoundary.tsx

75 lines
2.2 KiB
TypeScript
Raw Normal View History

2026-05-20 18:43:08 +09:00
import * as React from "react";
import { ErrorState } from "@/components/ui/error-state";
interface ErrorBoundaryState {
error: Error | null;
}
interface ErrorBoundaryProps {
children: React.ReactNode;
/** Render prop for full custom fallback */
fallback?: (error: Error, reset: () => void) => React.ReactNode;
/** Reset boundary when any value in this array changes (like `useEffect` deps) */
resetKeys?: unknown[];
/** Called once when a render error is caught */
onError?: (error: Error, info: React.ErrorInfo) => void;
}
/**
* Catches render-time errors anywhere below it and shows a fallback UI.
* Wrap the whole app at the root (catches everything) and optionally
* wrap individual routes/sections for finer-grained recovery.
*
* Note: does NOT catch errors inside event handlers, async code, or
* server-side rendering. For those, surface errors via React Query
* `onError` or `toast.error()`.
*/
export class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
state: ErrorBoundaryState = { error: null };
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { error };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
this.props.onError?.(error, info);
// eslint-disable-next-line no-console
console.error("[ErrorBoundary]", error, info);
}
componentDidUpdate(prevProps: ErrorBoundaryProps) {
if (!this.state.error) return;
const prev = prevProps.resetKeys ?? [];
const next = this.props.resetKeys ?? [];
if (
prev.length !== next.length ||
prev.some((v, i) => !Object.is(v, next[i]))
) {
this.reset();
}
}
reset = () => this.setState({ error: null });
render() {
const { error } = this.state;
if (!error) return this.props.children;
if (this.props.fallback) return this.props.fallback(error, this.reset);
return (
<div className="mx-auto max-w-3xl px-6 py-16">
<ErrorState
severity="error"
title="Something went wrong"
description="An unexpected error broke this view. You can try reloading just this section, or refresh the page."
detail={error.stack ?? error.message}
onRetry={this.reset}
/>
</div>
);
}
}