kokh log

yumikokhの開発日記

イベントハンドラ内でthrowされたエラーをErrorBoundaryでキャッチしたい

ErrorBoundaryはReact内でruntimeエラーが起こった際に、エラーをキャッチし、あらかじめ設定しておいたFallback UIを表示するための仕組みをもつコンポーネントのことを指します。React16で導入されました。

例えば、下記のようにコンポーネント内のレンダリングフェーズでエラーが投げられた場合、 ErrorBoundaryがエラーをキャッチして、 hoge ではなくfallbackである fuga を表示します。

ErrorBoundaryで囲っていない場合、画面がクラッシュしてしまいます。

export default function App() {
  throw new Error()
  return <div>hoge</div>
}

<ErrorBoundary fallbackRender={<div>fuga</div>}>
  <App />
</ErrorBoundary>

このとき落とし穴だったのが、ErrorBoundaryはイベントハンドラ内でthrowされたエラーはキャッチしない ということです。

明示されているのは旧バージョンのドキュメントですが、下記のように書かれています。

error boundary は以下のエラーをキャッチしません

Error Boundary – React

そもそも、イベントハンドラ内でエラーがthrowされ、ハンドリング内でcatchできていなかったとしても、レンダリングフェーズでのエラーと違いアプリケーション画面はクラッシュしません。

ユーザーのアクションによって起こったエラーであることがほとんどなので、ユーザーにエラー理由を伝えるようなフィードバックをしたいですね。

レアケースではあるかもしれませんが、 イベントハンドラから ErrorBoundary にエラーを伝搬させる方法もあるのでご紹介します。


react-error-boundary で簡単に実装できます。

下記のように useErrorBoundary から呼び出した showBoundary の引数にエラーを渡して実行することで、イベントハンドラーからエラーの伝播を行うことができます。

import { useErrorBoundary } from "react-error-boundary";

export default function App() {
  const { showBoundary } = useErrorBoundary();
  const clickCatchHandler = useCallback(() => {
    showBoundary(new Error());
  }, []);
  
  return (
    <div>
      <button onClick={clickCatchHandler}>キャッチできるエラー</button>
    </div>
  );
}

ライブラリ内の処理を見ると、内部的に error状態を監視するstateを切り替えることでレンダリングフェーズでのエラーを引き起こしてくれています。

https://github.com/bvaughn/react-error-boundary/blob/15f1ba286826cea5e191935e39bcd62b6a4d4ba1/src/useErrorBoundary.ts#L19-L43

はてなブログはgistじゃないとコード展開してくれないのか 🤔)


下記で動作を確認することができます。