Closed5

イベントハンドラー内でのエラーをError Boundaryでキャッチする方法

nissy-devnissy-dev

Error Boundaryは、コンポーネント内でthrowされたエラーをキャッチする仕組み
Suspenseも似ていて、コンポーネント内でthrowされたPromiseをキャッチする仕組み

できた理由としては、エラーがキャッチされなかった場合に React コンポーネントツリー全体をunmountしたかったということがありそう。

この決定については議論がありましたが、我々の経験上、壊れた UI をそのまま表示しておくことは、完全に削除してしまうよりももっと悪いことです。例えば、Messenger のような製品において壊れた UI を表示したままにしておくと、誰かが誤って別の人にメッセージを送ってしまう可能性があります。同様に、支払いアプリで間違った金額を表示することは、何も表示しないよりも悪いことです。

https://ja.reactjs.org/docs/error-boundaries.html#where-to-place-error-boundaries

https://sbfl.net/blog/2020/02/10/react-suspense-async/

nissy-devnissy-dev

一方でコンポーネント内でthrowされたエラーしかキャッチしないので、イベントハンドラー内で起きるエラーはキャッチできない

この点についてはReactのドキュメントでも触れられていて、イベントハンドラーで起きるエラーはその中でtry/catchしてほしいという雰囲気を感じる。
https://ja.reactjs.org/docs/error-boundaries.html#how-about-event-handlers

一方で、現実的にそれぞれのイベントハンドラーでtry/catch構文を追加させるのは大変で、エラーによって処理を分岐させるロジックも散らばってしまう傾向もある。できれば Error boundaries に、イベントハンドラーで生じるエラー処理周りも含めてエラー処理を集約させたい。

nissy-devnissy-dev

上記のDanさんのアドバイスを応用したライブラリがあった
非同期処理やイベントハンドラ内でのエラーを扱うためのカスタムHooksを提供している

カスタムHooksの原理はとても単純でコードは以下の通り。非同期処理やイベントハンドラ内で起きたエラーをsetStateを使ってstate にセットし、stateがセットされたら再びhooks内でエラーをthrowする。

function useErrorHandler(givenError?: unknown): (error: unknown) => void {
  const [error, setError] = React.useState<unknown>(null)
  if (givenError != null) throw givenError
  if (error != null) throw error
  return setError
}

https://github.com/bvaughn/react-error-boundary

このスクラップは2021/11/28にクローズされました