0
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】DogAPIで癒されようPart2

Posted at

はじめに

以前、javascript学習も兼ねてDog APIというAPIを叩いて癒されようという記事を書きました。
今回はReact学習するにあたり再びDogAPIを使ってみました。

今回作成したもの

image.png

おおまかにやっていることは以下の二つです。

1.画面ロード時にDogAPIを叩いてドロップダウンリストに表示する犬種情報を取得して表示
2.fetchボタンを押下するとDogAPIを叩き、ドロップダウンリストで選択した犬種情報をもつ画像情報を取得して表示

コード全体

おそらくゴミみたいなコードですが一応動くので載せておきます。

コード全体
Top.jsx
import { ChangeEvent, useEffect, useState } from "react";

export const Top = () => {
  const [dogImage, setDogImage] = useState<string>("");
  const [dogList, setDogList] = useState<Object>({});
  const [selectedDog, setSelectedDog] = useState<string[]>([]);

  //ドロップダウンで犬種を選択したときに情報をsetする
  const handleFormDogList = (event: ChangeEvent<HTMLSelectElement>): void => {
    const selectedDogData: string = event.target.value;
    const breedInfo: string[] = selectedDogData.split(" ");
    return setSelectedDog(breedInfo);
  };

  //fetchボタンを押下したときにAPIをたたいて画像情報をsetする
  const onClickShowDog = () => {
    //splitの関係で分割代入がうまくいかないので分岐して対応
    if (selectedDog.length === 1) {
      const [breed] = selectedDog;
      fetch(`https://dog.ceo/api/breed/${breed}/images/random`)
        .then((response) => {
          return response.json();
        })
        .then((json) => {
          return setDogImage(json["message"]);
        });
    } else {
      const [subBreed, breed] = selectedDog;
      fetch(`https://dog.ceo/api/breed/${breed}/${subBreed}/images/random`)
        .then((response) => {
          return response.json();
        })
        .then((json) => {
          return setDogImage(json["message"]);
        });
    }
  };

  //画面ロード時にドロップダウンリストに入れる情報の取得、画像の初期表示
  const getAllDogList = () => {
    fetch("https://dog.ceo/api/breeds/list/all")
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        return setDogList(data["message"]);
      });

    setSelectedDog(["affenpinscher"]);

    fetch(`https://dog.ceo/api/breed/affenpinscher/images/random`)
      .then((response) => {
        return response.json();
      })
      .then((json) => {
        return setDogImage(json["message"]);
      });
  };

  //初回マウント時に実行する処理を記載
  useEffect(() => {
    return getAllDogList;
  }, []);

  return (
    <div style={{ width: "100%" }}>
      <div style={{ display: "flex", alignItems: "center" }}>
        <p
          style={{
            backgroundColor: "gray",
            color: "#fff",
            padding: "10px 6px",
          }}
        >
          <span>https://dog.ceo/api/breed/</span>
          <select
            style={{ padding: "10px 40px" }}
            onChange={(e: ChangeEvent<HTMLSelectElement>) => {
              handleFormDogList(e);
            }}
          >
            {Object.entries(dogList).map(([breed, subBreedArr]) => {
              if (subBreedArr.length === 0) {
                return <option key={breed}>{breed}</option>;
              } else {
                return subBreedArr.map((subBreed: string) => {
                  const dogName: string = `${subBreed} ${breed}`;
                  return <option key={dogName}>{dogName}</option>;
                });
              }
            })}
          </select>
          <span>/images/random</span>
        </p>
        <button
          style={{
            backgroundColor: "blue",
            color: "#fff",
            marginLeft: "6px",
            padding: "15px 30px",
          }}
          onClick={onClickShowDog}
        >
          fetch
        </button>
      </div>

      <div style={{ marginTop: "20px" }}>
        <img style={{ width: "650px", height: "650px" }} src={dogImage}></img>
      </div>
    </div>
  );
};

各説明

1-①犬種リストの取得

まず初回マウント時の処理をuseEffectで記述しています。

  //初回マウント時に実行する処理を記載
  useEffect(() => {
    return getAllDogList;
  }, []);

実際に行う処理はgetAllDogListに書かれています。
ドロップダウンリストで使う犬種情報を取得するために"https://dog.ceo/api/breeds/list/all"を叩きます。

//画面ロード時にドロップダウンリストに入れる犬種情報の取得、画像の初期表示
  const getAllDogList = () => {
    //犬種情報の取得
    fetch("https://dog.ceo/api/breeds/list/all")
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        return setDogList(data["message"]);
      });

    //最初に選択される犬種と表示画像の管理
    setSelectedDog(["affenpinscher"]);

    fetch(`https://dog.ceo/api/breed/affenpinscher/images/random`)
      .then((response) => {
        return response.json();
      })
      .then((json) => {
        return setDogImage(json["message"]);
      });
  };

取得した情報は以下のJSONで返却されます。

JSON
{
        "affenpinscher": [],
        "african": [],
        "airedale": [],
        "akita": [],
        "appenzeller": [],
        "australian": [
            "kelpie",
            "shepherd"
        ],
        
        (省略)
        
}

1-②取得したJSON情報をドロップダウンリストに表示する

ドロップダウンリストの実装箇所です。

ドロップダウンリスト
<select
            style={{ padding: "10px 40px" }}
            onChange={(e: ChangeEvent<HTMLSelectElement>) => {
              handleFormDogList(e);
            }}
          >
            {Object.entries(dogList).map(([breed, subBreedArr]) => {
              if (subBreedArr.length === 0) {
                return <option key={breed}>{breed}</option>;
              } else {
                return subBreedArr.map((subBreed: string) => {
                  const dogName: string = `${subBreed} ${breed}`;
                  return <option key={dogName}>{dogName}</option>;
                });
              }
            })}
</select>

リストには取得したJSONのkeyを表示し、valueが空配列でなければkeyvalueを連結した文字列を表示することにします。(後の画像情報取得APIを叩くのに必要)

上記を実現するのに、dogList(取得したJSON)の中身をmapでぐるぐるして表示させたい。
でも、mapって配列に対してしか使えない。そんな時は...

Object.entries(オブジェクト名) を使いましょう。

keyvalueの組を要素に持つ配列を返してくれます。

上記の方法でオブジェクトの情報を配列で取得することが出来たので、あとはmapでぐるぐるしてあげてoptionタグでリストに表示を行っています。

2-① ドロップダウンリストで選択した犬種情報を管理する

リストで選択した情報はonChangeイベントで選択を検知して管理してあげます。

ドロップダウンリスト
<select
            style={{ padding: "10px 40px" }}
            onChange={(e: ChangeEvent<HTMLSelectElement>) => {
              handleFormDogList(e);
            }}
          >
           (省略)
</select>
onChangeイベント発火時の処理
 //ドロップダウンで犬種を選択したときに情報をsetする
  const handleFormDogList = (event: ChangeEvent<HTMLSelectElement>): void => {
    const selectedDogData: string = event.target.value;
    const breedInfo: string[] = selectedDogData.split(" ");
    return setSelectedDog(breedInfo);
  };

このあと画像情報取得API(https://dog.ceo/api/breed/${breed}/${subBreed}/images/random)を叩くのにあたり、
連結してリストに表示したkeyvalueを再度分離してURLに含む必要があるのでsplitを使っています。

2-②fetchボタン押下時に画像情報を取得し、取得画像を表示する

fetchボタン押下時にonClickイベントを発火させます。

fetchボタン
<button
          style={{
            backgroundColor: "blue",
            color: "#fff",
            marginLeft: "6px",
            padding: "15px 30px",
          }}
          onClick={onClickShowDog}
        >
          fetch
</button>
    
onClickイベント発火時の処理
//fetchボタンを押下したときにAPIをたたいて画像情報をsetする
  const onClickShowDog = () => {
    //splitの関係で分割代入がうまくいかないので分岐して対応
    if (selectedDog.length === 1) {
      const [breed] = selectedDog;
      fetch(`https://dog.ceo/api/breed/${breed}/images/random`)
        .then((response) => {
          return response.json();
        })
        .then((json) => {
          return setDogImage(json["message"]);
        });
    } else {
      const [subBreed, breed] = selectedDog;
      fetch(`https://dog.ceo/api/breed/${breed}/${subBreed}/images/random`)
        .then((response) => {
          return response.json();
        })
        .then((json) => {
          return setDogImage(json["message"]);
        });
    }
  };
画像表示場所
<div style={{ marginTop: "20px" }}>
        <img style={{ width: "650px", height: "650px" }} src={dogImage}></img>
</div>

おわり

備忘録でした。
useEffectの使い方、オブジェクトの中身を配列で取得、mapがネストするときにreturn書き忘れがち、といったことは経験を通した学びとなりました。
ドロップダウンのonChangeイベントで検知するイベントの型がChangeEvent<HTMLSelectElement>ということも知りました。Typescriptも満足に使えるようになりたいですね...

0
0
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
0
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?