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<Error | string | null>(null); const [isDialogOpen, setDialogOpen] = useState(false); useEffect(() => { .... }, []); function handleCloseDialog() { setDialogOpen(false); setError(null); } return ( <> {children} {isDialogOpen && error && ( <ErrorDialog actionName="Unhandled error" error={error} loggFeilmelding={true} onClose={handleCloseDialog} /> )} </> ); }
現時点で不足しているのは、useEffect 内で定義されたエラー処理自体です。
このセクションのコードはすべて useEffect 関数内に配置する必要があります!
まず、handleWindowError を定義します。これは、ウィンドウ オブジェクトのエラー イベント ハンドラーに渡されます。ここには何も不思議なことはありませんが、エラー イベントにはソース、行番号、列番号に関する情報も含まれていることに注目してください。収集すると価値があるかもしれません。
通常、この情報はエラー オブジェクト内にもありますが、これについてはさらに経験に基づいた調査を行う必要があります。おそらく、エラーイベントによって報告された行番号と列番号を常に保持する必要があるでしょうか?その場合、GlobalErrorHandler 内でこれの状態を保持することもできます (そして、エラーをログに記録するときにこれが送信されることを確認します)。
componentDidCatch(error: Error, errorInfo: ErrorInfo) { (error as any).isHandledByBoundary = true; .... }
handleUnhandledRejection ハンドラーも定義します。これは、Promise 内で発生したエラー用ですが、.catch() 句を書き忘れた場合です。
import { useState, useEffect, ReactNode } from 'react'; import { ErrorDialog } from '../Components/ErrorDialog'; type Props = { children: ReactNode; }; export function GlobalErrorHandler({ children }: Props) { const [error, setError] = useState<Error | string | null>(null); const [isDialogOpen, setDialogOpen] = useState(false); useEffect(() => { .... }, []); function handleCloseDialog() { setDialogOpen(false); setError(null); } return ( <> {children} {isDialogOpen && error && ( <ErrorDialog actionName="Unhandled error" error={error} loggFeilmelding={true} onClose={handleCloseDialog} /> )} </> ); }
その後、リスナーを設定し、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 が用意されています。
以上がGlobalErrorHandler: ErrorBoundary の指を通過するエラーをキャッチします。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。