今回は、React SPAでファイルを取得後にネットワークがオフラインになった場合にネットワークエラーページに遷移させるプログラムについて解説しました。データフェッチのタイミングでも同等のことができますが、今回はJS既存のイベントリスナーを使用して実装しています。
ご挨拶
ども!ブログネタのためにアプリを開発を始めたら、ブログの執筆する時間が捻出できなくなっている龍ちゃんです。ペース配分が難しいですね。
さて、今回は社内で定期開催されている「輪読会」で得た知見を発信する内容となります。今回取り扱う内容としては、「React SPAでサイトを覗いている際に、ネットワークが落ちたらエラー画面を表示する」となっています。実際に執筆していて「必要か?」ってなっていましたが、知らなかったのでまとめておきます。
それでは、さっくりと初めて行きましょう。
SPAとネットワークエラー
Single Page Application(SPA)の特徴では、以下の特徴があります。こちらの記事で、SSR・SSG・SPAの違いを図解で解説されています(超優良参考資料)。
SPAの面白いところは、表示に関するCSSやJSファイルはサーバーから一括で受け取り、クライアント側でAPIにアクセスを行いデータを取得して描画します。サーバーとの通信時にネットワークエラーが発生した場合、表示に関するデータごと取得できないのでクライアント側でネットワークエラーが表示されます。
ですが、サーバー側からのデータ取得時はオンラインで、その後オフラインになった場合では表示はあるけどエラーが吐きだされます。以下の赤枠部分ですね。
このエラーハンドリングに関しては、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の特殊な状態を意図的に発生させることができますね。
おわりに
ども!まったく知見のないところから、仕入れることができたので成長を感じれました。実際の要件で必要になるかはわかりませんが、知らなくてできないのと、知ってるけどやらないは大きく違うので、良い勉強です。
今回参考にした書籍は、「フロントエンド開発入門 プロフェッショナルな開発ツールと設計・実装」になります。月に一度は、技術書を読んでいきたいですね。
ではまた!