Kohei Blog

夫・父親・医療系エンジニア

ReactのErrorBoundaryとは何か

ErrorBoundary

コンポーネントツリーのどこかで例外が発生した場合、アプリケーション全体が影響を受けてしまう。アプリの規模が大きくなると、例外が発生した箇所を特定するのが難しくなってくる。

ErrorBoundaryは、特定のコンポーネントで例外が発生したとしても、アプリ全体に影響を与えずフォールバック用の UI を表示するコンポーネント

ErrorBoundaryコンポーネントの作成

ErrorBoundaryを実装するには、ライフサイクルメソッドの getDerivedStateFromError か、 componentDidCatch を使う必要がある。つまり、関数コンポーネントでのErrorBoundaryはできず、クラスコンポーネントを実装しないといけないみたい。

ErrorBoundary.tsx

import React, { ErrorInfo } from "react";

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

  static getDerivedStateFromError(): { hasError: boolean } {
    console.log("getDerivedStatefromError");
    return { hasError: true };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
    console.log("this.state.hasError", this.state.hasError);
    console.log(error);
    console.log(errorInfo);
  }

  render() {
    if (this.state.hasError) {
      console.log("render", this.state.hasError);
      return <>エラーが発生したよ!</>;
    }
    return <>{this.props.children}</>;
  }
}

export default ErrorBoundary;

ほぼ公式ドキュメントからの抜粋 error boundaryとは

  • getDerivedStateFromError() ... 名前のとおり、エラーをキャッチしてstateを更新するためのオブジェクト。更新するstate情報をreturnすることでsetState()される。

  • componentDidCatch() ... エラー情報をキャッチする。ErrorとErrorInfo

該当コンポーネントをErrorBoundaryコンポーネントで囲む

エラーを発生させるコンポーネントを作成。

BreakThings.tsx

export const BreakThings = () => {
  throw new Error("Something went wrong!");
};

App.tsx

import "./styles.css";
import SiteLayout from "./SiteLayout";
import ErrorBoundary from "./ErrorBoundary";
import { BreakThings } from "./BreakThings";

export default function App() {
  return (
    <div className="App">
      <SiteLayout
        menu={
          <ErrorBoundary>
            <BreakThings />
            <p>Menu</p>
          </ErrorBoundary>
        }
      >
        <>
          <h1>Heading</h1>
        </>
      </SiteLayout>
    </div>
  );
}

単一のコンポーネントをラップすると、それぞれでエラーが発生した場合、個別にfallbackコンポーネントが表示されます。

ただし、開発用サーバーだとスタックトレース情報が表示されてしまうので、アプリケーションをビルドした上で確認したほうが良さそう。

関数型で扱えるパッケージreact-error-boundary

react-error-boundaryを使用すれば、レンダリング時のエラーが扱いやすくなるみたい。

import {ErrorBoundary} from 'react-error-boundary'

function ErrorFallback({error, resetErrorBoundary}) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  )
}

const ui = (
  <ErrorBoundary
    FallbackComponent={ErrorFallback}
    onReset={() => {
      // reset the state of your app so the error doesn't happen again
    }}
  >
    <ComponentThatMayError />
  </ErrorBoundary>
)****

ドキュメントからの抜粋ですが、やはり関数型の方がシンプルで良き。

react-error-boundary

関連リンク