はじめに
以前、javascript学習も兼ねてDog APIというAPIを叩いて癒されようという記事を書きました。
今回はReact学習するにあたり再びDogAPIを使ってみました。
今回作成したもの
おおまかにやっていることは以下の二つです。
1.画面ロード時にDogAPI
を叩いてドロップダウンリストに表示する犬種情報を取得して表示
2.fetchボタンを押下するとDogAPI
を叩き、ドロップダウンリストで選択した犬種情報をもつ画像情報を取得して表示
コード全体
おそらくゴミみたいなコードですが一応動くので載せておきます。
コード全体
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で返却されます。
{
"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
が空配列でなければkey
とvalue
を連結した文字列を表示することにします。(後の画像情報取得APIを叩くのに必要)
上記を実現するのに、dogList
(取得したJSON)の中身をmapでぐるぐるして表示させたい。
でも、mapって配列に対してしか使えない。そんな時は...
Object.entries(オブジェクト名) を使いましょう。
key
とvalue
の組を要素に持つ配列を返してくれます。
上記の方法でオブジェクトの情報を配列で取得することが出来たので、あとはmapでぐるぐるしてあげてoptionタグ
でリストに表示を行っています。
2-① ドロップダウンリストで選択した犬種情報を管理する
リストで選択した情報はonChangeイベント
で選択を検知して管理してあげます。
<select
style={{ padding: "10px 40px" }}
onChange={(e: ChangeEvent<HTMLSelectElement>) => {
handleFormDogList(e);
}}
>
(省略)
</select>
//ドロップダウンで犬種を選択したときに情報を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
)を叩くのにあたり、
連結してリストに表示したkey
とvalue
を再度分離してURLに含む必要があるのでsplit
を使っています。
2-②fetchボタン押下時に画像情報を取得し、取得画像を表示する
fetchボタン押下時にonClickイベント
を発火させます。
<button
style={{
backgroundColor: "blue",
color: "#fff",
marginLeft: "6px",
padding: "15px 30px",
}}
onClick={onClickShowDog}
>
fetch
</button>
//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
も満足に使えるようになりたいですね...