ErrorBoundary は、React コンポーネントからスローされたエラーをキャプチャする素晴らしいツールです。エラー自体の性質と場所に応じて、カスタム エラー メッセージを提供できます。ただし、スローされるすべてのエラーが ErrorBoundary によって処理されるわけではありません。それらをどうするのですか?
非同期エラーと React の外部からスローされるエラーの両方を考慮すると、ErrorBoundary では不十分になります。これを軽減するために、アプリケーション内で GlobalErrorHandler と呼ばれるものを作成しました。 A) エラー ダイアログをポップアップ表示して、何かが間違っていることをユーザーに通知します。B) 調査して解決策を見つけることができるように、エラーをサーバーに記録します。
アイデアはシンプルです。アプリケーションのルートに GlobalErrorHandler が 1 つ必要です。このハンドラーは、ErrorBoundary によって捕捉されなかったエラーのみを処理する必要があります。さらに、それはユーザーによって簡単に却下されるべきであり、アプリケーションはまだ使用できると想定する必要があります。
したがって、戦略は次のとおりです。デフォルトでは、GlobalErrorHandler は子のレンダリング以外は何も行いません。ただし、2 つのイベント リスナーをセットアップし、ブラウザー内のすべてのエラー イベントと未処理拒否イベントをリッスンします。次に、エラーを調べて、すでに ErrorBoundaries によって処理されているかどうかを確認します。最後に、そうでない場合は、ダイアログをポップアップ表示して、どこかで問題が発生したことをユーザーに伝え、ユーザーがダイアログを閉じてアプリケーションの使用を継続できるようにします。
ErrorBoundary による処理に加えて不要なダイアログを表示してエンド ユーザーを悩ませる前に、まずエラーを尋ねることから始める必要があります。「すでに処理されましたか?」これに対する私の解決策は、エラー オブジェクト isHandledByBoundary に新しいフィールドを導入することです。これは、ErrorBoundary:
内で true に設定されます。
componentDidCatch(error: Error, errorInfo: ErrorInfo) { (error as any).isHandledByBoundary = true; .... }
これをすべての ErrorBoundary コンポーネント (およびキャッチされなかったエラーを処理するその他の機構) に配置すると、GlobalErrorHandler の定義を開始する準備が整います。
次に、GlobalErrorHandler のスケルトンを構築できます。これはその子を直接レンダリングし、他の場所で定義された「ErrorDialog」もレンダリングします。 (このコンポーネントをアプリケーション間で共有したい場合は、代わりに ErrorDialog を prop にすることができます。)
import { useState, useEffect, ReactNode } from 'react'; import { ErrorDialog } from '../Components/ErrorDialog'; type Props = { children: ReactNode; }; export function GlobalErrorHandler({ children }: Props) { const [error, setError] = useState(null); const [isDialogOpen, setDialogOpen] = useState(false); useEffect(() => { .... }, []); function handleCloseDialog() { setDialogOpen(false); setError(null); } return ( {children} {isDialogOpen && error && ( )} > ); }
現時点で不足しているのは、useEffect 内で定義されたエラー処理自体です。
このセクションのコードはすべて useEffect 関数内に配置する必要があります!
まず、handleWindowError を定義します。これは、ウィンドウ オブジェクトのエラー イベント ハンドラーに渡されます。ここには何も不思議なことはありませんが、エラー イベントにはソース、行番号、列番号に関する情報も含まれていることに注目してください。収集すると価値があるかもしれません。
通常、この情報はエラー オブジェクト内にもありますが、これについてはさらに経験に基づいた調査を行う必要があります。おそらく、エラーイベントによって報告された行番号と列番号を常に保持する必要があるでしょうか?その場合、GlobalErrorHandler 内でこれの状態を保持することもできます (そして、エラーをログに記録するときにこれが送信されることを確認します)。
function handleWindowError( message: string | Event, source?: string, lineno?: number, colno?: number, error?: Error ) { if (error && (error as any).isHandledByBoundary) { return true; } const errorMessage = error ? error : `Error: ${message} at ${source}:${lineno}:${colno}`; setError(errorMessage); setDialogOpen(true); return true; }handleUnhandledRejection ハンドラーも定義します。これは、Promise 内で発生したエラー用ですが、.catch()-clause.
を書き忘れた場合に使用されます。
function handleWindowError( message: string | Event, source?: string, lineno?: number, colno?: number, error?: Error ) { if (error && (error as any).isHandledByBoundary) { return true; } const errorMessage = error ? error : `Error: ${message} at ${source}:${lineno}:${colno}`; setError(errorMessage); setDialogOpen(true); return true; }次に、リスナーを設定し、GlobalErrorHandler がレンダリングされなくなったときにリスナーを削除するだけです。
function handleWindowError( message: string | Event, source?: string, lineno?: number, colno?: number, error?: Error ) { if (error && (error as any).isHandledByBoundary) { return true; } const errorMessage = error ? error : `Error: ${message} at ${source}:${lineno}:${colno}`; setError(errorMessage); setDialogOpen(true); return true; }return ステートメントは、もちろん、useEffect にフィードしている関数から戻る場所です。これにより、コンポーネントがレンダリングされるときにイベントのリッスンと処理が開始され、コンポーネントがレンダリングされなくなったら停止することが保証されます。
したがって、非同期ソースからスローされるか、React コンポーネントの外部からスローされる、React アプリケーション内の厄介なエラーを処理するための GlobalEventHandler が用意されています。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3