くるくる回るローディング画面の実装方法 – Reactなら簡単

データの読込み時に、クライアント側でくるくる回るアイコンが表示されることがあると思います。本稿ではこのスピナーアイコンを表示させる仕組みと、Semantic UI Reactのコンポーネントを使った具体的な実装方法を解説します。Material UIにも同様のコンポーネントがあり、本稿を読めばMaterial UIでも問題なく構築できると思います。英語ではくるくる回るアイコンのことをSpinner(スピナー)と呼んでいますので、以下本稿でも同アイコンをスピナーと呼びます。

スピナー表示の基本的な仕組み

Fetch又はaxiosでバックエンドにリクエストをする場合、リクエスト本体コードと、レスポンスを受ける.then以下のコード、それにエラーを処理する.catchのコードを設けると思います(あるいはasync await構成)。スピナーはリクエスト開始時に表示され、.then又は.catch処理に入ったときに消えている必要がありますので、この状態を管理するためにuseStateを使います(以下、具体的にisLoadingとします)。すなわち、本体コードが読み込まれバックエンドにリクエストを始めた状態をtrueとしてisLoadingに保存し、リスポンスを得られたらisLoadingにfalseを格納します。そして三項演算子により、isLoadingがtrueならスピナーを、同Falseなら表なりグラフなり目的のコンポーネントを表示させます。

{ 条件 ? 真の場合の処理 : 偽の場合の処理 }

スピナー表示の具体例

下記は、ボタンに対するonClickでsubmitToBack関数が呼び出され、同関数内でaxiosを使ってバックエンドにリクエストを求める事例です。

SendRequest.js

import React, { useState } from "react";
import ShowData from "./components/ShowData";
import Loading from "./components/Loading";
import { getAPI } from "../axiosGetAPI";

function SendRequest() {
const [ isLoading, setIsLoading ] = useState(false);
const [ resData, setResData ] = useState(null);

const submitToBack = (e) => {
e.preventDefault();
setIsLoading(true);
getAPI.get("/pathToAPI", {
params:{
input: input
}
}).then(res => {
setResData(res.data);
setIsLoading(false);
}).catch(error => {
console.log(error);
setIsLoading(false);
})

return (
< div>
< button onClick={submitToBack}) >
データを取得する
</ button>
{ isLoading ? <Loading /> : < ShowData data={resData}/> }
</ div>
);
};

export default SendRequest;

以下、順を追って説明いたします。

インポート

上の4行で必要なライブラリーやコンポーネントをインストールしています。1行目はローカルで状態を管理する(≒変数を格納する)useStateです。2行目はデータをダウンロードした後に表示させたいコンポーネントです。本稿ではShowDataという名称のコンポーネントとしていますが、具体的な内容はテキスト、Chart.jsなどのグラフ、ダウンロードの実行など様々なものがあり得ると思います。3行目はスピナーのコンポーネントです。こちらは冒頭でもご紹介したようにSemantic UI React又はMaterial UIのものをそのまま使うのが便利だと思います。最後の4行目は別ファイルでコンフィギュレーション設定したaxiosを読み込んでいます。axisoは別ファイルに書かずとも直接本コンポーネントで記述することもできます。axiosの詳細については私のこちらの記事、Reactでのaxiosの使い方【外部APIの取得方法】をご覧ください。なお、fetchを使う場合も基本的な構造は同じです。

import React, { useState } from "react";
import ShowData from "./components/ShowData";
import Loading from "./components/Loading";
import { getAPI } from "../axiosGetAPI";

2本のuseState

SendRequest全体は関数コンポーネントで構築し、関数の内側でuseStateを2本設定しています。1行目は基本的な仕組みのところで解説したisLoadingです。初期値はfalseとします。初期値をtrueとしてまうと、このSendRequestコンポーネントが読み込まれた時点からスピナーが回ってしまいます。2行目はバックエンドからのレスポンスを格納するためのuseState、初期値はnullです。

const [ isLoading, setIsLoading ] = useState(false);
const [ resData, setResData ] = useState(null);

axiosを含む関数 – 本体部分

submitToBack関数の引数(e)はeventのeです。通常はボタンをクリックすると画面がリロードされ、useState他既存の状態が全て消えてしまうので、1行目のe.preventDefault()でリロードを防ぎます。2行目でisLoadingにtrueを格納します。この瞬間から、後段の三項演算子の条件が満たされ、ユーザーの画面上ではスピナーが回り始めます。getAPIの部分はaxisoに係るコードです。axiosオブジェクトには別のファイルで設定したドメインが格納されています。1つ目の引数にはエンドポイントを、2番目の引数にクエリパラメーターを格納します。

const submitToBack = (e) => {
e.preventDefault();
setIsLoading(true);
getAPI.get("/pathToAPI", {
params:{
input: input
}
})

axiosを含む関数 – .thenの部分

レスポンスが正しく得られると(ステータス200)、得られたレスポンスに対してthen以下が処理されます。1行目ではレスポンスデータ(res.data)をresDataステートに保存しています。無事にレスポンスを得られたので、2行目ではisLoadingにfalseを格納しています。isLoadingがfaleになるとスピナーは止まります。

}).then(res => {
setResData(res.data);
setIsLoading(false);
})

axiosを含む関数 – .catchの部分

catchの部分ではまずエラーを受けて処理します。ここでは単にコンソール画面にエラーの内容を表示させています。2行目では.thenの時と同じくisLoadingにfalseを格納しています。エラーの場合もスピナーを止めるためです。

}).catch(error => {
console.log(error);
setIsLoading(false);
})

JSXの部分

ボタンにはonClickを持たせ、クリックすると上段で定義したsubmitToBack関数が呼びだれます。ボタンに続くのが三項演算子です。isLoadingがtrueのとき(リクエスト後レスポンス前)は、スピナーであるLoadingコンポーネントを表示し、isLoadingがfalseのとき(レスポンス後)は、グラフや表などを含むShowDataコンポーネントを表示します。ShowDataコンポーネントにはpropsとしてレスポンスで得られたresDataを渡しています。

return (
< div>
< button onClick={submitToBack}) >
データを取得する
</ button>
{ isLoading ? <Loading /> : < ShowData data={resData}/> }
</ div>
);

スピナーを使わないとエラーが出る場合

ロードの時間が短時間で、スピナーを表示させる必要がないきはShowDataコンポーネントをそのまま配置しますが、ShowDataコンポーネント内で、Charts.jsやreact-csvなどの外部ライブラリーを使うときはそのまま置くとエラーが出ることがあります。レスポンスが得られるまではresDataがnullなためです。そこで下記のように、AND演算子&&を用いてresDataがtrueの場合に限り(データが存在する場合はtrueとなる)、ShowDataを表示させるようにします。このAND演算子&&の使い方は、三項演算子でelseにあたる三項目がない状態に相当します。

{ 条件 && 真の場合の処理 }

{ resData && < ShowData data={resData}/> }

スピナーそのもの

下記はスピナーそのものであるLoadingコンポーネントの一例です。このコンポーネントを前述の三項演算子なしにそのままJSXに組み込むと、永遠にくるくる回ります。スピナーには他にも幾つか異なるスタイルがありますので、詳細はSemantic UI Reactの公式ページをご覧ください。Elementsの中にLoaderがあると思います。

Loading.js

import React from "react";
import { Dimmer , Loader } from "semantic-ui-react";

function Loading({ inverted = true, content="Loading..."}) {
return (
< Dimmer inverted={inverted} active={true}>
< Loader content={content}/>
</ Dimmer>
)
}

export default Loading;

今日も最後まで読んで頂きありがとうございました。