プログラミング

React ErrorBoundaryを作ってみた

hebishima.shogo

はい、hebiです。

Reactの集約エラーハンドラーとなるErrorBoundaryを作ってみました。

react-error-boundaryを利用して作ろうかなと思いましたが、少しクセが強かったので、自前で作成しました。

完成形です。

import { useState, useEffect, ReactNode } from "react";
import { useNavigate } from "react-router-dom";

type ErrorBoundaryProps = {
  children: ReactNode;
};

function useErrorBoundary(): [boolean, ErrorEvent | null] {
  const [hasError, setHasError] = useState(false);
  const [errorEvent, setErrorEvent] = useState<ErrorEvent | null>(null);

  useEffect(() => {
    const errorHandler = (e: ErrorEvent) => {
      setHasError(true);
      setErrorEvent(e);
    };

    // エラーハンドラを設定
    window.addEventListener("error", errorHandler);

    return () => {
      // コンポーネントがアンマウントされる際にエラーハンドラをクリーンアップ
      window.removeEventListener("error", errorHandler);
    };
  }, []);

  return [hasError, errorEvent];
}

function ErrorBoundary({ children }: ErrorBoundaryProps) {
  const [hasError, errorEvent] = useErrorBoundary();
  const navigate = useNavigate();

  if (hasError) {
    const errorInfo = {
      message: errorEvent?.message,
      filename: errorEvent?.filename,
      lineno: errorEvent?.lineno,
      colno: errorEvent?.colno,
    };
    // エラーページへの遷移
    navigate("/error", {
      state: errorInfo,
    });
    return <></>;
  }

  // エラーがない場合は、通常のコンポーネントを描画。
  return <>{children}</>;
}

export default ErrorBoundary;

コンポーネント内で例外が発生するとwindow.addEventListener(“error”, errorHandler)で設定したerrorHandler関数が実行されます。

useErrorBoundary()がhasError, errorEventを返却するので、hasErrorがtrueの場合は、エラーページへ遷移します。

注意点として、react-error-boundaryを利用した場合も同じですが、非同期処理内で例外が発生した場合はキャッチされません。try-catchでthrowするか、then-catchの場合は、以下のようにスローすることでキャッチされることを確認してます。(try-catchでもsetStateが必要かも?要確認。)

const [, setState] = useState(null);
setState(() => {
  throw e;
});

以上です。最後までお読みいただきありがとうございました。

スポンサーリンク
ABOUT ME
hebi
hebi
エンジニア
フルスタックエンジニアとして活躍中。
HTML5プロフェッショナル認定Level1、Level2所持者です。

未経験の方でも簡単にプログラミングを学べるようにと情報を発信しております。
記事URLをコピーしました