3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React / TypeScript】ローディングを実装する方法

Posted at

画面を読み込むときにAPIを呼び出してデータが取得されるまでローディングマーク(丸がぐるぐるするやつ)を表示したい、という場面は多いでしょう。

今回はReact + TypeScript + react-loadingを使って実装します。
また、APIを実装するのは手間なので以下のAPIを叩いてデータを取得します。

https://api.thecatapi.com/api/images/get?format=json&results_per_page=10&type=gif (可愛い猫ちゃんの画像が取得されます。)

react-loadingとは?

ローディングアイコンを実装するためのサードパーティ製ライブラリです。

最新のコミットが2年前なので開発はほぼ止まっているようです。

以下サンプルコードのようにpropsで色やアイコンの大きさを調整することができます。

import React from 'react';
import ReactLoading from 'react-loading';
 
const Example = ({ type, color }) => (
    <ReactLoading type={type} color={color} height={667} width={375} />
);
 
export default Example;

環境

  • TypeScript 4.8.4
  • React 18.0.21
  • react-loading 2.0.3
  • Ubuntu20.04

事前準備

まずはreactのプロジェクトを作成します。

$ npx create-react-app --template typescript loading

続いて、react-loadingをプロジェクトにインストールします。

$ cd loading
$ npm install react-loading

正常にインストールできれば準備完了です。

ディレクトリ構成

ディレクトリ構成は以下の通りです。

loading
├── src
    ├── components
        ├── image.ts # APIのレスポンスの型を定義するファイル
        └── Images.tsx # 画面を描画するコンポーネント
        └── useFetchImages.tsx # APIから画像を取得するカスタムフック

実装例

APIから取得するデータの型定義

https://api.thecatapi.com/api/images/get?format=json&results_per_page=10&type=jpg で取得できるjsonデータは「id」「url」「source_url」という3つのプロパティを持ちます。(型はいずれもstring)

レスポンスの型をImageとして定義しましょう。

export type Image = {
  id: string;
  url: string;
  source_url: string;
};

画面を描画する


import  { useEffect} from 'react';
# react-loadingをインポートする
import ReactLoading  from "react-loading";

# Image型をインポート
import { Image } from './image';
import { useGetImages } from './useGetUsers';



export const Images = () => {
  const { isLoading, getImages, images } = useGetImages();
  useEffect(() => getImages(), []);

  return (
    <>
      {isLoading ?
        <ReactLoading
          type="spin"
          color="black"
          height="20px"
          width="20px"
          className="mx-auto"
        /> : 
        images.map((image: Image) => (
          <div key={ image.id}>
            <img src={image.url} style={ {width:"150px", height:"150px"}} />
          </div>
        ))
      }
    </>
  );
};

APIから画像を取得するカスタムフック


import axios from 'axios';
import { useCallback, useState } from 'react';
import { Image } from './image';

export const useGetImages = () => {
  const [isLoading, setIsLoading] = useState(false);
  const [images, setImages] = useState<Image[]>([]);

  const getImages = useCallback(() => {
    setIsLoading(true);
    axios.get<Image[]>('https://api.thecatapi.com/api/images/get?format=json&results_per_page=10&type=jpg')
      .then((res) => {
        setTimeout(() => {
          setImages(res.data);
          setIsLoading(false)
        }, 3000);
      })
      .catch(() => {
        alert('にゃーん');
        setIsLoading(false);
      })
  },[images]);

  return { isLoading, getImages, images };
};

重要なポイントは以下の3点です。

  • ローディング状態をboolean型のState isLoadingとして定義する。(ローディング中:true, ローディング中ではない:false )
  • API呼び出しを開始したらisLoadingをtrueに切り替える。成否にかかわらずAPI呼び出しが完了したらisLoadingをfalseに変更する。
  • Image.tsxではisLoadingがtrueであるときにローディングアイコンを表示する。isLoadingがfalseであるときには取得したデータを表示する。

また、API呼び出しやisLoading Stateの状態更新のようなUI描画と直接関係のない処理はカスタムフックに切り出すとImage.tsxの見通しがよくなります。

参考資料

Reactに入門した人のためのもっとReactが楽しくなるステップアップコース完全版
react-loading -npm
独自フックの作成

3
5
0

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
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?