Error Boundary — その概要、React Nativeコンポーネント、エラー処理

著者: IT Sectr 公開日: 2026-05-27 読了時間: 8 分

Error Boundaryは、子コンポーネントツリー内のJavaScriptエラーをキャッチし、クラッシュページの代わりにフォールバックインターフェースを表示するReactコンポーネントです。React Nativeのコンテキストでは、致命的でないレンダリングエラーが発生した際にアプリケーションの完全なクラッシュを防ぎます。React Documentation, 2024によると、error boundaryは子コンポーネントのrenderメソッド、ライフサイクルフック、コンストラクタ内のエラーをキャッチし、アプリケーションが動作を継続できるようにします。React Nativeでは、モバイルアプリはF5で再読み込みできないため、これは特に重要です — ユーザーはセッション全体を失います。

重要なポイント

  • Error Boundary — 子ツリー内のレンダリングエラーをキャッチするReactコンポーネント
  • ComponentDidCatch — エラーとスタック情報を受け取るライフサイクルメソッド
  • Fallback UI — 壊れたコンポーネントの代わりに表示されるバックアップインターフェース
  • React Nativeはアプリケーションの完全なクラッシュを防ぐためにError Boundaryを使用
  • 制限 — Error Boundaryは非同期コードやイベントハンドラ内のエラーをキャッチしない

Error Boundaryとは

Error Boundaryは、レンダリングエラーが発生した際のグレースフルデグラデーションのためのReactメカニズムです。React 16(2017年)で、2つのライフサイクルメソッド(static getDerivedStateFromErrorまたはcomponentDidCatch)のいずれかを実装するラッパーコンポーネントとして導入されました。Error Boundaryにより、空の白い画面やアプリケーションの完全なクラッシュの代わりに、ユーザーに意味のあるメッセージを表示できます。

Error Boundaryの成り立ち

React 16以前は、render内の未処理のエラーはDOMツリー全体のアンマウントを伴う完全なアプリケーションクラッシュを引き起こしていました。Webアプリケーションでは白い空画面を意味し、React Nativeではホーム画面に戻る完全なクラッシュを意味しました。Reactチームは、宣言的UIのためのcatchブロックの類似物としてError Boundaryを導入し、Erlang言語の “let it crash” アプローチから概念を借用しました。

React Nativeにおける重要性

React Nativeでは、Error Boundaryがないと、レンダリングエラーが発生した際にアプリケーションが完全にクラッシュします。ユーザーは回復オプションなしに現在のセッション全体を失います。React NativeにおけるError Boundaryは非常に重要です。モバイルアプリはWebページのように再読み込みできないため、ユーザーセッションは不可逆的に失われ、ユーザーは最初からやり直さなければなりません。

React NativeにおけるError Boundaryの仕組み

Error BoundaryはReactツリーレベルで動作します。子コンポーネントがrenderまたはライフサイクル内でエラーをスローすると、Reactはツリー全体をアンマウントせず、階層内の最も近いError Boundaryに制御を渡します。BoundaryはgetDerivedStateFromErrorを呼び出し、state.hasError = trueに設定し、壊れたコンポーネントブランチの代わりにフォールバックUIをレンダリングします。

typescript
import React, { Component, ErrorInfo, ReactNode } from "react"

interface Props {
    children: ReactNode
    fallback?: ReactNode
}

interface State {
    hasError: boolean
    error?: Error
}

class ErrorBoundary extends Component<Props, State> {
    constructor(props: Props) {
        super(props)
        this.state = { hasError: false }
    }

    static getDerivedStateFromError(error: Error): State {
        return { hasError: true, error }
    }

    componentDidCatch(error: Error, info: ErrorInfo) {
        console.error("Caught by boundary:", error)
        Crashlytics.recordException(error)
    }

    render() {
        if (this.state.hasError) {
            return this.props.fallback || <FallbackUI />
        }
        return this.props.children
    }
}

getDerivedStateFromErrorはフォールバックUIをレンダリングするための状態を設定します — これは変更をコミットする前のレンダーフェーズ中に呼び出される静的メソッドです。componentDidCatchはコミットフェーズで実行され、副作用(ロギング、Crashlyticsへのクラッシュレポート送信、分析)を目的としています。2つのメソッドは、UI状態管理と副作用の間で責任を分離します。

Error Boundaryコンポーネントの作成

Error Boundaryを作成するには、getDerivedStateFromErrorおよび/またはcomponentDidCatchメソッドを持つクラスコンポーネントを実装する必要があります。関数コンポーネントはError Boundaryになれません — Reactはライフサイクルメソッドへのアクセスが必要なため、この機能をクラスコンポーネントでのみサポートしています。react-error-boundaryライブラリは、利便性のためにフックベースのAPIを備えた既成の実装を提供します。

typescript
// React NativeでのError Boundaryの使用例
import { ErrorBoundary } from "react-error-boundary"

const FallbackComponent = ({ error, resetError }: FallbackProps) => (
    <View style={styles.container}>
        <Text>問題が発生しました</Text>
        <Text>{error.message}</Text>
        <Button title="再試行" onPress={resetError} />
    </View>
)

const App = () => (
    <SafeAreaView>
        <ErrorBoundary FallbackComponent={<FallbackComponent />}>
            <UserProfile userId={"123"} />
        </ErrorBoundary>
        <BottomNavigation />
    </SafeAreaView>
)

ラッパーレベル — Error Boundaryは階層のさまざまなレベルに配置できます。アプリケーションルートに1つのグローバルBoundaryを置くと、エラー時にフォールバックUIが表示されますが、ナビゲーションは維持されます。画面レベルで複数のBoundaryを使用すると、エラーを分離できます。1つの画面が壊れても、残りは独立して機能し続けます。react-error-boundaryはuseErrorBoundaryフックを介してリセットメカニズムを簡素化し、再読み込みなしで状態をリセットできます。一般的なプロジェクトでは、React Nativeアプリケーションに3レベルのBoundaryスキームが最適と考えられています。

Error Boundaryの状態リセット

エラー発生後、ユーザーはhasErrorをfalseにリセットして子ツリーを再レンダリングする “再試行” ボタンをクリックできます。リセットメカニズムは、再読み込みなしでアプリケーション機能を復元するために重要です。react-error-boundaryでは、onResetコールバックが使用され、キャッシュのクリア、データの再取得、ツリーの上位での状態更新が可能です。

Error Boundaryの制限

Error Boundaryは非同期エラーをキャッチしません — setTimeout、setInterval、Promise、async/await内のエラーです。Reactはレンダーサイクルとライフサイクルフックの外で発生するエラーをインターセプトできません。これらは異なる実行コンテキストで実行されるためです。非同期エラーに対しては、ハンドラ内に個別のtry-catchを配置するか、グローバルなunhandledrejectionイベントハンドラが必要です。

イベントハンドラ

onClick、onChange、その他のイベントハンドラ内のエラーは、Reactレンダリングの外部で実行されるため、Error Boundaryによってキャッチされません。イベントハンドラのエラー処理は、try-catchを使用してハンドラ自体の中で行う必要があります。react-error-boundaryライブラリは、イベントハンドラから最も近いBoundaryにエラーをスローするためのuseErrorHandlerフックを提供します。

サーバーサイドレンダリングとNext.js

Error BoundaryはNext.jsやGatsbyのサーバーサイドでは機能しません。getDerivedStateFromErrorメソッドとcomponentDidCatchメソッドはSSR中に呼び出されません。ライフサイクルメソッドはブラウザでのみ利用可能だからです。サーバーエラーには、個別の戦略が必要です:getServerSidePropsでのtry-catch、error.jsフォールバックページ(Next.js 13+)、またはグローバルミドルウェア。

React Nativeのネイティブレイヤー

React Nativeでは、Error Boundaryはネイティブモジュールレベルのクラッシュを防ぎません。ネイティブクラッシュ(segfault、メモリ不足、ネイティブ例外)はObjective-CまたはJavaレベルで発生し、JavaScriptレイヤーには到達しません。ネイティブクラッシュには、Crashlytics NDK(Android)またはKSCrash(iOS)が必要です。Error BoundaryはReact NativeアプリケーションのJavaScriptレイヤーのみを保護します。

Error Boundaryのベストプラクティス

Error Boundaryは論理モジュールの境界に配置します:画面ごとに1つのBoundary、サードパーティウィジェットごとに1つ、複雑なフォームごとに1つです。これによりエラーが分離され、ユーザーはアプリケーションの他の部分で作業を続行できます。ルートBoundaryは常に存在する必要があります — 共通のナビゲーションコンポーネントやプロバイダでの重大なエラーに備えて。各Boundaryは自身のインターフェースフラグメントに責任を持ち、エラー発生時に隣接するコンポーネントに影響を与えません。

ロギングと監視

常にcomponentDidCatchを介してCrashlyticsまたはSentryにエラーを渡します。コンテキスト(画面名、userId、アプリバージョン、ナビゲーションパラメータ)を追加します。Sentryでは、クラッシュに至るまでのユーザーアクションのシーケンスであるbreadcrumbsが利用可能です。非致命的エラーの頻度を分析するには、イシューごとにグループ化されたCrashlyticsダッシュボードを使用します。

フォールバックUI

ベアなフォールバックは使用せず、意味のあるインターフェースを作成します。React Nativeの推奨セット:エラーメッセージ(ユーザーフレンドリーで技術的でないもの)、“再試行”ボタン、サポートまたはチャットへのリンク。空のViewは避けてください — ユーザーはアプリが完全にクラッシュしたと思い、閉じてしまいます。フォールバックはアプリケーション全体のデザインに統合される必要があります。

Error Boundaryのテスト

各Error BoundaryをReact Testing LibraryまたはReact Native Testing Libraryを使用してテストします。レンダリング時にエラーをスローするトリガーコンポーネントを作成し、フォールバックUIが表示されることを確認します。統合テストでは、異なるError Boundary状態(通常、エラー、リセット後)でstorybookを使用します。Boundaryの自動テストにより、コンポーネントが変更された場合でも、フォールバックUIが本番環境で正しく機能し続けることが保証されます。各Boundaryのテストカバレッジは、React Nativeプロジェクトのコードレビューの必須要件であるべきです。

よくある質問

Error Boundaryが関数コンポーネントで機能しないのはなぜですか?

ReactはError Boundaryをクラスコンポーネントでのみ実装します。componentDidCatchとgetDerivedStateFromErrorのライフサイクルメソッドへのアクセスが必要だからです。関数コンポーネントにはそのようなメソッドがありません。react-error-boundaryライブラリは、使いやすさのためにフックベースのAPIを備えた既成のクラスラッパーを提供します。

Error Boundaryはパフォーマンスにどのように影響しますか?

影響は最小限です — Error Boundaryは子ツリーのレンダリングごとに状態チェックを追加します。state.hasErrorの比較は定数時間のO(1)操作です。エラーがない場合、オーバーヘッドはありません。エラーが発生した場合にのみ、BoundaryがフォールバックUIの追加レンダリングを実行します。

すべてのコンポーネントをError Boundaryでラップする必要がありますか?

いいえ、2–3レベルで十分です:アプリケーション全体のルートBoundary、各ナビゲーションブランチの画面Boundary、重要なウィジェット(支払いフォーム、マップ、チャット)のローカルBoundary。過剰なBoundaryの使用は、大きな利益なしにアーキテクチャを複雑にします。

React 18+でError BoundaryはSuspenseとどのように連携しますか?

Error BoundaryとSuspenseは独立しています:Suspenseはローディング(React 18+での保留中のPromise)をキャッチし、Error Boundaryはレンダリングエラーをキャッチします。これらは組み合わせることができます:<ErrorBoundary><Suspense><Component /></Suspense></ErrorBoundary>。ローディング中はSuspenseが最初にトリガーされ、ロードされたコンポーネントのエラー時にはError Boundaryがトリガーされます。

ReactにおけるError Boundaryとtry-catchの違いは何ですか?

try-catchは同期命令コード内のエラーをキャッチしますが、JSXレンダリングエラーをインターセプトできません。Error Boundaryは宣言的UI向けに特別に設計されています:render、ライフサイクルフック、子コンポーネントのコンストラクタ内のエラーをインターセプトします。これはReactレンダリングの特性上、try-catchにはできないことです。

まとめ

  • Error Boundary — フォールバックUI表示を伴うレンダリングエラーキャッチ用のReactコンポーネント
  • ComponentDidCatch — エラーロギング用メソッド、getDerivedStateFromError — UI状態管理用
  • React Nativeは完全なアプリケーションクラッシュ防止にError Boundaryを必要とする
  • 制限 — 非同期エラー、イベントハンドラエラー、SSR、ネイティブレイヤーをキャッチしない
  • react-error-boundary — 簡単なプロジェクト統合のためのフックベースAPIを備えた既成ライブラリ
  • ラッパーレベル — ルート、画面(推奨)、重要なウィジェット用ローカル
  • フォールバックUIは意味のあるものであるべき:エラーメッセージ、再試行ボタン、サポート連絡先

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください