React SPAでネットワークが落ちているときにエラー画面表示

React:SPA時のネットワークエラー画面遷移

今回は、React SPAでファイルを取得後にネットワークがオフラインになった場合にネットワークエラーページに遷移させるプログラムについて解説しました。データフェッチのタイミングでも同等のことができますが、今回はJS既存のイベントリスナーを使用して実装しています。

ご挨拶

ども!ブログネタのためにアプリを開発を始めたら、ブログの執筆する時間が捻出できなくなっている龍ちゃんです。ペース配分が難しいですね。

さて、今回は社内で定期開催されている「輪読会」で得た知見を発信する内容となります。今回取り扱う内容としては、「React SPAでサイトを覗いている際に、ネットワークが落ちたらエラー画面を表示する」となっています。実際に執筆していて「必要か?」ってなっていましたが、知らなかったのでまとめておきます。

それでは、さっくりと初めて行きましょう。

SPAとネットワークエラー

Single Page Application(SPA)の特徴では、以下の特徴があります。こちらの記事で、SSR・SSG・SPAの違いを図解で解説されています(超優良参考資料)。

SPAの特徴

SPAの面白いところは、表示に関するCSSやJSファイルはサーバーから一括で受け取り、クライアント側でAPIにアクセスを行いデータを取得して描画します。サーバーとの通信時にネットワークエラーが発生した場合、表示に関するデータごと取得できないのでクライアント側でネットワークエラーが表示されます。

ですが、サーバー側からのデータ取得時はオンラインで、その後オフラインになった場合では表示はあるけどエラーが吐きだされます。以下の赤枠部分ですね。

SPAの問題点

このエラーハンドリングに関しては、axiosでも実装することができます。今回は、ブラウザの標準の機能を使って実装してみようと思います。もし、データ通信部分でaxiosを使用している場合は、データ通信に関するエラーになりますので、一元管理することが開発としてもいいかもしれません。実際は、サーバーとAPIサーバーからのデータの取得は感知することができないくらい、早く通信が発生すると思います。そういった点でも、axiosにまとめるほうがいいですね。

実装

構成としては、react-error-boundaryを実装します。参考資料としては、こちらを参照してください。構成に必要なファイルとしては、以下になります。

  • ネットワークエラーをハンドリングするためのError:NetworkError
  • react-error-boundary用のファイル:ErrorBoundaryComponent
  • ネットワークイベント用リスナー:NetworkStatusConfig

各項目解説していきます。

ネットワーク用エラー

まずは、Errorを継承したネットワークエラーを作成します。既存のエラーを拡張して作成することで、エラー発生時の切り分けを行うことができます。

export class NetWorkError extends Error {
  constructor() {
    super('network error');
    this.name = 'NetWorkError';
  }
}

react-error-boundary用のファイル

こちらでは、エラーが起きた際に画面の差し替えを行ってくれます。先ほど、拡張したエラーと送信されてきたエラーを比べてネットワークエラーを判別しています。

import { ErrorBoundary, FallbackProps } from 'react-error-boundary';

import { NetWorkError } from './Error/NetworkError';

type Props = {
  children: React.ReactNode;
};
export const ErrorBoundaryComponent = (props: Props) => {
  const { children } = props;

  return <ErrorBoundary FallbackComponent={ErrorFallback}>{children}</ErrorBoundary>;
};

const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) => {
  if (error instanceof NetWorkError) return <div>ネットワークエラー</div>;
  return (
    <>
      <button className="" onClick={resetErrorBoundary}>
        リトライ
      </button>
    </>
  );
};

ネットワークイベント用リスナー

最後に、ネットワークイベント「オフライン」を監視するコンポーネントを作成します。ネットワークの監視イベントは、イベントハンドラーを用いて監視します。エラーが発生した場合は、先ほど作成したネットワーク用エラーをreact-error-boundaryのカスタムフックでエラーを伝搬させています(const { showBoundary } = useErrorBoundary();)。

import { useEffect } from 'react';
import { useErrorBoundary } from 'react-error-boundary';

import { NetWorkError } from './Error/NetworkError';

type Props = {
  children: React.ReactNode;
};

export const NetworkStatusConfig = (props: Props) => {
  const { children } = props;
  const { showBoundary } = useErrorBoundary();
  const throwNetworkError = () => {
    showBoundary(new NetWorkError());
  };

  useEffect(() => {
    window.addEventListener('offline', throwNetworkError);
    return () => {
      window.removeEventListener('offline', throwNetworkError);
    };
  });

  return <>{children}</>;
};

全体構成

それぞれ設定したコンポーネントを作成します。ネットワークイベント監視内で、react-error-boundaryのカスタムフックを使用して、エラーイベントを伝搬させているため、react-error-boundaryのコンポーネントの中に、ネットワークイベント監視用コンポーネントを設定する必要があります。

import { ErrorBoundaryComponent } from './ErrorBoundary';
import { NetworkStatusConfig } from './NetworkStatusConfig';

type Props = {
  children: React.ReactNode;
};

export const UtilitiesConfig = (props: Props) => {
  const { children } = props;
  return (
    <>
      <ErrorBoundaryComponent>
        <NetworkStatusConfig>
            {children}
        </NetworkStatusConfig>
      </ErrorBoundaryComponent>
    </>
  );
};

確認

せっかく実装したので、確認をしていきたいと思います。オフライン状態を自発的に起こすには、Googleの開発者ツールを使用しましょう。

「F12」を押して、ネットワークタブを開きましょう。以下の画面を参考にドロップリストを開いてください。

こちらでは、ネットワークの状態をデフォルトで「高速」「低速」「オフライン」の3つを意図的に発生させることができます。こちらで、SPAの特殊な状態を意図的に発生させることができますね。

おわりに

ども!まったく知見のないところから、仕入れることができたので成長を感じれました。実際の要件で必要になるかはわかりませんが、知らなくてできないのと、知ってるけどやらないは大きく違うので、良い勉強です。

今回参考にした書籍は、「フロントエンド開発入門 プロフェッショナルな開発ツールと設計・実装」になります。月に一度は、技術書を読んでいきたいですね。

ではまた!

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です