【実務・中級編】 Error Boundariesによるエラーハンドリング – React実践ガイド

Reactの「崖っぷち」を守る:Error Boundariesでアプリケーションの崩壊を防ぐ技術

現場でコードを書いていると、どうしても避けられないものがある。「予期せぬ実行時エラー」だ。APIから予期せぬnullが飛んできたり、コンポーネントのレンダリング中にプロパティへのアクセスでクラッシュしたり。

Reactは、標準のままだとコンポーネントツリーのどこか一箇所でエラーが発生すると、ツリー全体がアンマウントされ、画面が真っ白(いわゆる「ホワイトスクリーン・オブ・デス」)になる。ユーザーから見れば、アプリが突然死したようにしか見えない。

これを防ぐための「最後の砦」が Error Boundaries(境界) だ。今日は、単なるマニュアルの解説を超えて、実務でどう使い倒すべきか、その極意を伝授しよう。

—

Error Boundariesの核心:なぜ「クラスコンポーネント」なのか?

まず、初心者が必ずぶつかる疑問がある。「なぜHooksで書けないの?」。
実は、`getDerivedStateFromError` と `componentDidCatch` という2つのライフサイクルメソッドは、執筆時点のReactにおいてクラスコンポーネントでしか定義できない。

これはReactの設計思想上の制約だ。エラー境界は、「レンダリング中に発生したエラーをキャッチする」という極めて低レイヤーな責務を負っている。関数コンポーネントはあくまで「値の変換器」として設計されており、ライフサイクルを管理する能力を持たない。だからこそ、エラーという「システムの状態異常」を扱うために、あえてクラスベースのガードマンを配置するのだ。

—

実践:現場でそのまま使える「ErrorBoundary」実装

以下のコードは、僕が実際に現場のプロジェクトでテンプレートとして使っているものだ。これをそのままコピーして、`components/ErrorBoundary.jsx` として保存してほしい。

import React from ‘react’;

// エラーが起きた時に表示するフォールバックUIのプロップス型定義(必要に応じてTypeScript化してね)
export class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
// 初期状態はエラーなし
this.state = { hasError: false };
}

// 1. エラーをキャッチしてstateを更新し、フォールバックUIを表示させる
static getDerivedStateFromError(error) {
return { hasError: true };
}

// 2. エラー情報をログサービス(Sentry等)に送信する場所
componentDidCatch(error, errorInfo) {
// ここでエラー監視ツールに飛ばすのが定石
console.error(“ErrorBoundaryがエラーを検知しました:”, error, errorInfo);
}

render() {
if (this.state.hasError) {
// 3. ユーザーに見せるエラー画面
return this.props.fallback || (

);
}

// エラーがなければ子コンポーネントをそのまま描画
return this.props.children;
}
}

—

どこに配置すべきか?設計の指針

ErrorBoundaryをどこに置くかは、アプリのUXを左右する重要な判断だ。

1. トップレベル(Rootに近い場所)に一つ置く:
アプリ全体が死ぬのを防ぐため、最低でも `App.js` の直下には配置しよう。これで、致命的なバグがあっても「画面全体が真っ白」という最悪の事態は避けられる。
2. 重要な機能の境界に置く(推奨):
例えば、「サイドバー」「メインコンテンツ」「ウィジェット」のように、UIの塊ごとにErrorBoundaryで囲む。こうすることで、メインコンテンツでエラーが出ても、サイドバーは操作可能な状態を維持できる。これが「機能単位で壊れる」という、モダンなフロントエンドの振る舞いだ。

注意:キャッチできないエラーもある

実務で一番ハマりやすいのがこれだ。Error Boundariesは、以下のエラーをキャッチできない。

  • イベントハンドラ内でのエラー: `onClick` 等の中で発生したエラーは、Reactのレンダリングサイクル外なので、通常の `try-catch` で処理する。
  • 非同期コード: `setTimeout` や `Promise` 内のエラーも同様だ。
  • サーバーサイドレンダリング(SSR): サーバー側では当然動かない。

「ErrorBoundaryを置いたから安心」ではなく、「レンダリングの安全装置」と「非同期エラーのハンドリング」は別物だと認識しておくこと。

—

最後のアドバイス:エラーを「隠す」な

ErrorBoundaryでエラーをキャッチした時、そのまま無視してはいけない。必ず `componentDidCatch` の中で `Sentry` や `Datadog` のような監視ツールにエラーを送信すること。

フロントエンドの仕事は、バグを出さないことではなく、「バグが発生した時に、いかに早くそれを検知し、ユーザーへの影響を最小限に留めるか」だ。

この記事が、あなたのプロジェクトをより強固なものにする助けになれば嬉しい。何か詰まったら、いつでもコンポーネントのツリーを俯瞰して、どこに「境界」を引くべきか考えてみてほしい。それこそが、シニアへの第一歩だ。

コメント

タイトルとURLをコピーしました