【Next.js】読み込み時にAPIからデータを取ってくる
概要
Next.jsでクリックしたときに外部APIからデータを取ってきて表示するとかある。
最初にそのページにアクセスした時に外部APIからデータを表示させたい場合getServerSideProps
で処理するメモ。
外部API
今回は犬の画像を検索できるサービスのAPIを利用してみる
APIのURLは下記になる。
https://dog.ceo/api/breeds/image/random
取得できるJSONファイルのデータは下記
{
"message": "https://images.dog.ceo/breeds/terrier-patterdale/patterdale-terrier-1330018870tnN.jpg",
"status": "success"
}
外部APIを利用する際の注意点
外部APIから画像を取得する場合に以下のようなエラーが出たりする。
Error: Invalid src prop (https://images.dog.ceo/breeds/chihuahua/n02085620_7700.jpg) on `next/image`, hostname "images.dog.ceo" is not configured under images in your `next.config.js`
See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host
こちら外部ドメインの画像を使用するとエラーが出てる模様なので、next.config.js
に下記のように使用するドメインを指定してあげる。
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
domains: ['images.dog.ceo'], //ここにドメインを指定
},
}
module.exports = nextConfig
実際の流れ
今回はNext.jsを使用するが、作業ファイルはpages/index.js
で完結させる。
以下のような使用とする。
- ページを表示したらAPIから画像のURLを取ってくる
- クリックしたらAPIから画像URLを取ってきて画像を切り替える
全体のコード
import Image from 'next/image'
import { useState } from 'react'
import styles from '../styles/Home.module.css'
const searchDog = async () => {
const response = await fetch("https://dog.ceo/api/breeds/image/random");
const res = await response.json();
return res;
}
export default function Home({ initialCatImageUrl }) {
const [catImage, setCatImage] = useState(initialCatImageUrl);
const handleClick = async () => {
const res = await searchDog();
setCatImage(res.message);
}
return (
<div className={styles.container}>
<main>
<h1>犬の画像</h1>
</main>
<div style={{ position: 'relative', width: 400, height:400 }}>
<Image src={catImage} layout="fill" objectFit="contain" alt='犬' />
</div>
<button onClick={handleClick}>画像を検索</button>
</div>
)
}
export const getServerSideProps = async () => {
const res = await searchDog();
console.log(res);
return {
props: {
initialCatImageUrl: res.message
}
};
};
htmlの表示部分
index.js
はHOMEとなってるかと思うが、ここにhtmlとしてブラウザに表示させる部分を記述する。他の処理はいったん省略。
export default function Home({ initialCatImageUrl }) {
const [catImage, setCatImage] = useState(initialCatImageUrl);
return (
<div>
<h1>猫の画像</h1>
<div style={{ position: 'relative', width: 400, height:400 }}>
<Image src={catImage} layout="fill" objectFit="contain" alt='犬' />
</div>
<button onClick={handleClick}>画像を検索</button>
</div>
)
}
後ほど説明するが、HOMEの引数にある{ initialCatImageUrl }
はgetServerSideProps
から受け取るプロパティ名である。
また、「最初にページを読み込んだ時」「ボタンをクリックした時」に画像のURLが変わるのでuseSate
でcatImage
を管理します。初期値はgetServerSideProps
から受け取ったinitialCatImageUrl
を設定しておきます。
クリックしたらhandleClick
という関数を設定しておく。
APIから画像データを取ってくる
まずは、APIから画像データを取ってくる関数を処理。
const searchDog = async () => {
const response = await fetch("https://dog.ceo/api/breeds/image/random");
const res = await response.json();
return res;
}
クリックしたときと読み込み時と使いまわす必要があるので、APIから画像を取ってくる処理をsearchDog
という関数にして取得したデータをreturn
で返しておく。
こちらは非同期処理として、async
としてawait
で処理している。
またこちらはgetServerSideProps
でもserachDog
関数を使う必要があるので、Homeの関数コンポーネントの外に記述しておく。
ボタンをクリックしたら呼び出す
ボタンをクリックしたらAPIから画像データを取ってくるsearchDog
関数からデータを取ってくる。
もちろん非同期処理なのでhandleClick
はasync
を指定してawait
でsearchDog
を呼び出す。
その後、useSate
のsetCatImage
にres.message
で画像のURLをセットする。
*message
となってるが、こちらのAPIは画像のURLがmessage
プロパティにある。
const handleClick = async () => {
const res = await searchDog();
setCatImage(res.message);
}
getServerSidePropsで読み込み時にAPIからデータを取ってくる
getServerSideProps
を設定しない場合、クリックするまで画像が読み込まれないのでスペースができてしまう。
それを防ぐためにアクセスした際の処理として、getServerSideProps
を設定する。
export const getServerSideProps = async () => {
const res = await serachDog();
return {
props: {
initialCatImageUrl: res.message
}
};
};
画像を読み込むためにgetServerSideProps
で読み込む際にsearchDog
関数を実行して、props
にinitialCatImageUrl
というプロパティ名で画像のURLを設定してreturn
で返してあげる。
この値を、HOMEの引数から受け取って、useState
の初期値として、設定してあげれば、Image
コンポーネントのsrc
属性に設定したcatImage
で画像が表示される。
まとめ
いったん、これでアクセス時に画像を読み込む処理とクリック時に読み込む処理は終わり。
あとは読み込み時にローディングなどuseState
でやってみるとかはまた今度。
Discussion