概要
ErrorBoundary はレンダリング中に発生した JavaScript エラーを捕捉し、クラッシュする代わりにフォールバック UI を表示する。
Next.js の error.tsx はルートセグメント単位の捕捉だが、ErrorBoundary は任意のコンポーネントツリーに対して個別に適用できる。
インストール
# 追加インストールは不要
実装例
// src/components/ErrorBoundary.tsx
import { Component, type ErrorInfo, type ReactNode } from "react";
type Props = {
fallback: ReactNode;
children: ReactNode;
};
type State = {
hasError: boolean;
error: Error | null;
};
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: ErrorInfo) {
// ログ収集サービス(Sentry 等)への送信はここで行う
console.error("ErrorBoundary caught:", error, info.componentStack);
}
render() {
if (this.state.hasError) {
return this.props.fallback;
}
return this.props.children;
}
}
// src/components/UserProfile.tsx(エラーを投げる可能性のあるコンポーネント)
type Props = { userId: number };
export function UserProfile({ userId }: Props) {
if (userId <= 0) {
throw new Error("無効なユーザー ID です");
}
return <p className="text-sm">ユーザー ID: {userId}</p>;
}
// src/app/profile/page.tsx
import { ErrorBoundary } from "@/components/ErrorBoundary";
import { UserProfile } from "@/components/UserProfile";
function ErrorFallback() {
return (
<div className="rounded border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
プロフィールの読み込みに失敗しました。
</div>
);
}
export default function ProfilePage() {
return (
<main className="p-6">
<ErrorBoundary fallback={<ErrorFallback />}>
<UserProfile userId={-1} />
</ErrorBoundary>
</main>
);
}
ポイント
getDerivedStateFromErrorでエラー発生時の state を更新し、フォールバック UI に切り替えるcomponentDidCatchはエラーログの送信に使う(Sentry 等への連携はここ)fallbackを props で受け取る設計にすると、用途ごとに異なるフォールバック UI を渡せるerror.tsx(Next.js)はルートセグメント全体を覆うが、ErrorBoundaryは特定のウィジェット単位に適用できる- イベントハンドラ内のエラー(
onClick等)は捕捉されない。それらは try/catch で扱う