1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

いろいろ試してみた!Reactでのローディング画面実装方法

Posted at

はじめに

業務で、データを取得している間は画面を見せないようにするローディング画面を作る事があったので、備忘のためにその方法をまとめていきます。

環境

以下のものを使っています。

ライブラリ バージョン
React 18.2.0
TypeScript 5.2.2
Vite 5.2.0

useStateをつかったローディング画面

やろうと思ったときにパッと思い浮かぶのはこれかなと思います。
そんなに難しいことはないので、早速コードを見ていきましょう。

StateLoading.tsx
import { useEffect, useState } from "react";

// API用URL
const url =
  "https://api.open-meteo.com/v1/forecast?latitude=35.6895&longitude=139.6917&hourly=temperature_2m&timezone=Asia%2FTokyo";

// APIレスポンスの型定義
interface WeatherData {
  hourly: {
    temperature_2m: number[];
    time: string[];
  };
}

const StateLoading = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [data, setData] = useState<WeatherData>();

  // APIデータ取得用処理
  const fetchData = async () => {
    try {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
    } catch (e) {
      console.log(e);
    } finally {
      setIsLoading(false);
    }
  };

  // コンポーネント読み込み時に取得
  useEffect(() => {
    fetchData();
  }, []);

  if (isLoading) {
  // ロード中の場合はローディング画面
    return (
      <>
        <h1>Loading...</h1>
      </>
    );
  } else {
  // ロードが終わるとデータ表示
    return (
      <>
        <h2>Temperature Forecast</h2>
        {data && data.hourly && (
          <ul>
            {data.hourly.time.map((time, index) => (
              <li key={time}>
                {time}: {data.hourly.temperature_2m[index]}°C
              </li>
            ))}
          </ul>
        )}
      </>
    );
  }
};

export default StateLoading;

今回は天気を取得できるAPIを使っています。
ポイントは以下です。

stateを使って分岐する

isLoadingというstateを用意しました。
この値がtrueの場合には読込中画面を出力します。

isLoadingfalseに更新されると、表示したい画面(ここではデータの一覧)を出力するようにしています。

stateの初期値はtrue

コンポーネント読み込み時は当然データ読み込みが終わっていないので、isLoadingtrueとします。
そして、finallyisLoadingfalse、つまり読み込み完了とします。
しかし、これだとエラー時にも読み込み完了となってしまいます。
そのため、場合によってはエラー用のstateも用意して、エラー画面を表示することもできます。

Suspenseをつかったローディング画面

Reactの18以降を使っているのであれば、Suspenseコンポーネントが使えます。
これは、子要素の読み込みが完了するまで、フォールバックを表示させることができるコンポーネントです。
※フォールバック:機能や性能を制限して動かすこと

どういうことか、コードを見てみます。

SuspenseLoading
import { Suspense } from "react";

// API用URL
const url =
  "https://api.open-meteo.com/v1/forecast?latitude=35.6895&longitude=139.6917&hourly=temperature_2m&timezone=Asia%2FTokyo";

// APIレスポンスの型定義
interface WeatherData {
  hourly: {
    temperature_2m: number[];
    time: string[];
  };
}

let weatherData: WeatherData;

// APIデータ取得用処理
const fetchWeatherData = async (): Promise<WeatherData> => {
  const res = await fetch(url);
  const data = await res.json();
  weatherData = data;
  return data;
};

// コンポーネント描画処理
const WeatherDataComponent = () => {
  if (!weatherData) {
    // Promiseをthrow
    throw fetchWeatherData();
  }

  return (
    <>
      <h2>Temperature Forecast</h2>
      {weatherData.hourly && (
        <ul>
          {weatherData.hourly.time.map((time, index) => (
            <li key={time}>
              {time}: {weatherData.hourly.temperature_2m[index]}°C
            </li>
          ))}
        </ul>
      )}
    </>
  );
};

const SuspenseLoading = () => {
  return (
    <Suspense fallback={<h1>Loading...</h1>}>
      <WeatherDataComponent />
    </Suspense>
  );
};

export default SuspenseLoading;

少しコードが複雑になりましたが、ここでの動きは大きく2つです。

コード概要

着目すべきはSuspenseLoadingコンポーネントです。
ここではSuspenceコンポーネントを使用しています。

fallbackには読み込みが完了するまでの間表示させたいコンポーネントを指定します。
コンポーネントの子要素には、表示させたいコンポーネントを指定します。

Suspenseの使い方は大まかにこのような形となります。

しかし、子要素のコンポーネントに制約があるため、他の処理が若干複雑になっています。

Promiseをスローする

Suspenceの制約は上記の公式サイトに以下のように書かれています。

サスペンスコンポーネントをアクティブ化できるのはサスペンス対応のデータソースだけです。これには以下が含まれます:

Relay や Next.js のようなサスペンス対応のフレームワークでのデータフェッチ
lazy を用いたコンポーネントコードの遅延ロード
use を用いたプロミス (Promise) からの値の読み取り

詳細な解説は避けますが、最後の部分に着目します。
子要素の中ではPromiseをスローします。

これにより、SuspenseコンポーネントはスローされたPromiseが解決されるまでは子要素の描画を保留します。
その代わり、fallbackに指定したコンポーネントを描画することができます。

まとめ

ローディング画面を標示する方法について調べました。
業務ではstateを使った方法で実装していました。

Suspenseについてはまったく知らなかったので、今回の記事を通して少し理解を深めることができました。

しかし、そもそもPromise関連の知識も不足しているので、周辺知識も合わせて抑えておきたいと思いました。

参考にしたサイト

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?