最も単純な ErrorBoundary コンポーネントをカプセル化して、React 例外を処理する

最も単純な ErrorBoundary コンポーネントをカプセル化して、React 例外を処理する

序文

React 16から、子コンポーネントで発生したエラーを捕捉し、エラーログを記録し、ダウングレードコンテンツを表示できるエラー境界の概念が導入されました。具体的な公式ウェブサイトのアドレスは

エラー境界は、コンポーネント エラーによってページ全体が使用不能になり、画面が空白になるのを防ぎます。エラー境界は、グレースフル デグラデーションを使用して代替 UI を提示します。エラー境界は、レンダリング中、ライフサイクル中、およびコンポーネント ツリー全体のコンストラクター内でエラーをキャプチャできます。 React 16 以降では、エラー境界でキャッチされないエラーが発生すると、React コンポーネント ツリー全体がアンマウントされます。

エラー境界の意味

  • 一部のUIがクラッシュしますが、Webアプリ全体がクラッシュするわけではありません

ページを閲覧しているときに、バックエンドから返される例外やフロントエンドでのエラーチェックが原因で、ユーザーエクスペリエンスが悪くなることがあります。妻と一緒に電車に座って鍋を食べながら歌を歌っていると、突然盗賊に襲われ、エラーメッセージが表示されることを想像してみてください。金額を設定するときや重要なページを表示するときなど、一部のシナリオでは、エクスペリエンスが非常に悪くなります。たとえば、ゲームで500をチャージしましたが、インターフェイスの理由により、チャージNaNが表示されます。この表示は、表示されないよりも迷惑です。ただし、JS例外キャプチャは誰もがよく知っていると思いますので、ビジネスコードのtry-catchパッケージで十分です。ただし、コンポーネントで例外をキャプチャするには、React が提供するError Boundary機能を使用し、 componentDidCatchフックを使用してページ例外をキャプチャして、例外がページ全体に広がらないようにし、ページに空白の画面が表示されるのを効果的に防ぐ必要があります。

公式サイトの実装方法

👉 クラス コンポーネントが 2 つのライフサイクル メソッド static getDerivedStateFromError() または componentDidCatch() のいずれか (または両方) を定義すると、エラー境界になります。エラーがスローされたら、static getDerivedStateFromError() を使用して代替 UI をレンダリングし、componentDidCatch() を使用してエラー メッセージを出力します 👈

ErrorBoundaryクラスはReact.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具);
    this.state = {hasError: false };
  }
  静的 getDerivedStateFromError(エラー) {
    // 次のレンダリングで劣化した UI を表示できるように状態を更新します
    {hasError: true } を返します。
  }
  コンポーネントDidCatch(エラー、エラー情報) {
    // エラー ログをサーバーに報告することもできます logErrorToMyService(error, errorInfo);
  }
  与える() {
    if (this.state.hasError) {
      // ダウングレードされた UI をカスタマイズしてレンダリングできます。 return <h1>Something went wrong.</h1>;
    }
    this.props.children を返します。
  }
}

その後、通常のコンポーネントとして使用できます。

<エラー境界>
  <マイウィジェット />
</エラー境界>

エラー境界は JavaScript のcatch {}同様に機能しますが、 Reactコンポーネントにのみ適用される点が異なります。 classコンポーネントのみがエラー境界コンポーネントになることができます。ほとんどの場合、エラー境界コンポーネントを一度宣言して、アプリケーション全体で使用すれば十分です。これを使用すると、ラップされたコンポーネント内のエラーやthrow new Error()によってスローされた例外がエラー境界コンポーネントによってキャッチされ、フォールバック UI として表示されます。

設定可能なErrorBoundaryをカプセル化します

公式サイトがエラー境界コンポーネントをどのように実装しているかを理解した後、 return <h1>Something went wrong</h1>直接記述する代わりに、 ErrorBoundaryコンポーネントをカプセル化して便利なホイールを作成できます。 react-reduxの原則を学んだ後、高階コンポーネントを使用してreactコンポーネントをラップし、データとメソッドをstoreにグローバルに挿入できることがわかりました。同様に、高階コンポーネントを使用して、エラーをキャプチャできる react コンポーネントにラップすることもできます。

1. 設定可能なErrorBoundaryクラスコンポーネントを作成する

公式サイトのErrorBoundaryと比較すると、パラメータを受け入れることで、ログの報告方法と表示されるUI動的に設定できます。受信UIについては、 reactコンポーネントまたはReact Elementとして受け入れられるように設定できます。また、コンポーネントを通じてパラメータを渡すことができるため、基礎となる UI で特定のエラー情報を取得できます。

  • componentDidCatch(): エラーログ処理用のフック関数
  • static getDerivedStateFromError() : スローされたエラーをパラメータとして受け取り、状態を更新するための値を返します。
ErrorBoundaryクラスはReact.Componentを拡張します。
  状態 = { エラー: false };
  静的 getDerivedStateFromError(エラー) {
    {エラー}を返します。
  }
  コンポーネントDidCatch(エラー、エラー情報) {
    エラーが発生した場合
      // レポート ログは、親コンポーネントによって挿入された関数を通じて実行されます。this.props.onError(error, errorInfo.componentStack);
    }
  }
  与える() {
    const { フォールバック、 FallbackComponent } = this.props;
    const { error } = this.state;
    if (エラー) {
      const fallbackProps = {エラー};
      //React要素かどうかを判定する
      React.isValidElement(フォールバック)の場合{
        フォールバックを返します。
      }
      //コンポーネントメソッド if (FallbackComponent) {
        <FallbackComponent {...fallbackProps} /> を返します。
      }
      throw new Error("ErrorBoundary コンポーネントをフォールバック UI に渡す必要があります");
    }
    this.props.children を返します。
  }
}

この方法では、基盤となるUI表示と錯誤日志動的に取得できるため、コンポーネントの柔軟性が向上します。ただし、別の問題もあります。サーバーが突然 503 または 502 で失敗し、フロントエンドが応答を取得できなくなる場合があります。このとき、コンポーネントはエラーを報告しますが、しばらくすると正常に戻ります。より良い方法は、ユーザーがErrorBoundaryによってカプセル化されたコンポーネント内のメソッドをクリックして、ページを更新せずにエラー コンポーネントを再読み込みすることです。この時点で、カバーする必要があるコンポーネントは、 ErrorBoundary処理するメソッドを公開する必要があります。

1. ErrorBoundary に、挿入されたリセット メソッドがあるかどうかを検出するメソッドを追加します。リセット メソッドがある場合は、それを実行し、エラー状態をリセットしてエラー状態を false にします。

リセットエラー境界 = () => {
  this.props.onReset() の場合、 this.props.onReset() になります。
  this.setState({ エラー: false });
};

2. レンダリング用に render に関数コンポーネント タイプを追加します。リセット メソッドとエラー情報は、処理のために現在のコンポーネントにパラメータとして渡すことができます。

 与える() {
    const { fallback、 FallbackComponent、 fallbackRender } = this.props;
    const { error } = this.state;
    if (エラー) {
      const フォールバックプロパティ = {
        エラー、
        リセットエラー境界: this.resetErrorBoundary、
      };
      ...
      fallbackRender の typeof === "function") の場合は fallbackRender(fallbackProps) を返します。
      ...
    }
    this.props.children を返します。
  }

2. ErrorBoundaryを高階関数でラップして返す

「react」からReactをインポートします。
「./core」からDefaultErrorBoundaryをインポートします。
const catchreacterror = (境界 = DefaultErrorBoundary) => 内部コンポーネント => {
  プロパティを返す => (
    <境界 {...props}>
      <InnerComponent {...props} />
    </境界>
  );
};

使用とテスト

クリックして増加するデモでは、数値が特定の値に達すると例外がスローされます。ここでは、クラス コンポーネントと Function コンポーネントが例外を開始するコンポーネントとしてテストされます。

  • 例外を引き起こしたコンポーネント
//関数コンポーネント const fnCount1 = ({ count }) => {
  if (count == 3) throw new Error("count is three");
  <span>{count}</span> を返します。
};
//クラスコンポーネント class fnCount2 extends React.Component {
  与える() {
    const { count } = this.props;
    if (count == 2) throw new Error("count is two");
    <span>{count}</span> を返します。
  }
}
  • エラー例外を処理するための関数コンポーネント
const errorbackfn = ({ エラー: { メッセージ }, resetErrorBoundary }) => (
  <div>
    <p>問題が発生しました</p>
    <pre>{メッセージ}</pre>
    <button onClick={resetErrorBoundary}>もう一度お試しください</button>
  </div>
);
  • エラー例外を処理するための共通コンポーネント
const errorbackcom = () => <h1>エラーが発生しました。元に戻すことはできません</h1>;
  • テストコンポーネント
//例外を開始したコンポーネントをラップし、エラー編集を処理できる高階コンポーネントを返します。const SafeCount1 = catchreacterror()(fnCount1);
const SafeCount2 = catchreacterror()(fnCount2);
//メインコンポーネントをテストする const App = () => {
  定数[count, setCount] = useState(0);
  const ListenError = (arg, info) => console.log("Error: " + arg.message, info); //エラーが発生したときのコールバック const onReset = () => setCount(0); //リセットがクリックされたときのコールバック return (
    <div className="アプリ">
      <セクション>
        <button onClick={() => setCount(count => count + 1)}>+</button>
        <button onClick={() => setCount(count => count - 1)}>-</button>
      </セクション>
      <時間 />
      <div>
        クラスコンポーネント:
        <セーフカウント2
          カウント={count}
          フォールバックレンダリング={errorbackfn}
          onReset={onReset}
          onError={ListenError}
        />
      </div>
      <div>
        機能コンポーネント:
        <セーフカウント1
          カウント={count}
          フォールバックコンポーネント={errorbackcom}
          onError={ListenError}
        />
      </div>
    </div>
  );
}; 

ミッション完了!

発生した問題とその概要

反応エラー境界が万能ではない場合が多々あります。例えば、

  • イベントエラー

上記の例では、this.o が存在しないため、エラーが報告されます。Window.onerror はこれをキャプチャできますが、エラー境界はキャプチャできません。

  • 非同期コード

サーバーサイドレンダリングとエラー境界自体

要約する

  • コンポーネントを抽出✔
  • バグレポート✔
  • UI 抽象化 ✔
  • エラーリセット✔
  • アンフックモード ✖
  • サーバー ✖

ここまで、この記事を読んでいただきありがとうございます。お役に立てれば幸いです。React のエラー境界について大まかに理解し、簡単なErrorBoundaryただし、最適化できるポイントはまだたくさんあります。ご不明な点がありましたら、お気軽にご指摘ください。 ErrorBoundary と react の詳細については、123WORDPRESS.COM の他の関連記事にも注目してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • React でのポータルとエラー境界処理の実装
  • Reactエラー境界コンポーネント処理
  • React 16における例外処理の詳細な説明
  • Reactワークフローとエラー境界の実装プロセスの説明

<<:  MySQL 8.0.3 RCがリリースされようとしています。変更点を見てみましょう。

>>:  MySQL データベース内の同じテーブルを同時にクエリして更新する方法

推薦する

Dockerでイメージを削除する方法

dockerでイメージを削除するコマンドはdocker rmiですが、このコマンドを実行してもイメー...

Dockerは単一のイメージを使用して複数のポートにマッピングします

必要:公式サイトのリソースサーバーは確かに1つのインスタンスでは使えず、複数のインスタンスを一緒に使...

Grafana+Prometheus を使用して MySQL サービスのパフォーマンスを監視する

Prometheus (プロメテウスとも呼ばれる) 公式サイト: https://prometheu...

IE をフリーズさせる HTML コード

任意のテキスト エディターを開き、次のコードをコピーして、たとえば SomeFilename.htm...

Vue での Vue.prototype の使用に関する詳細な説明

目次1. 基本的な例2. インスタンスプロトタイプのスコープを設定する3. グローバル変数の登録と使...

Centos7.3は起動時に自動的に起動または指定されたコマンドを実行します

Centos7では、/etc/rc.d/rc.localファイルの権限が削減されており、実行権限があ...

Ubuntu の空き容量を増やす 5 つの簡単な方法

序文ほとんどの人は、システム ディスク ストレージが少ないときにこの操作を実行するか、Linux シ...

<td></td> タグの境界線スタイルがブラウザに表示されない問題の解決方法

質問: 360ブラウザの互換モードなど、一部のブラウザでは、 <td style="...

MySQL マスターとスレーブの不整合とその解決策の詳細な説明

1. MySQL マスタースレーブ非同期1.1 ネットワーク遅延MySQLのマスタースレーブレプリケ...

Linux dirnameコマンドの具体的な使い方

01. コマンドの概要dirname - ファイル名からディレクトリ以外のサフィックスを削除しますd...

MySQL インデックスクエリ最適化スキルを習得するための記事

序文この記事では、DBA がいないチームが参考にできるように、MySQL の一般的な使用に関するヒン...

HTML のキャンバスに基づくスクリーンショットのデモ

冒頭に書いた以前、Renren で JS ベースのスクリーンショット ソリューションについて説明した...

HTML でマウスが停止したときに行全体の色 (tr) を変更する方法

純粋な CSS を使用して、マウスが行の上を通過するときに行の背景色を変更し、その行にフォーカスがあ...

MySQLのインデックス

序文早速本題に入りましょう。これからお話しするのは次のマインドマップです。まずは印象をつかんでくださ...

MySQL 5.7 の同時レプリケーションにおける暗黙のバグの分析

序文当社の MySQL オンライン環境のほとんどはバージョン 5.7.18 を使用しています。このバ...