はじめに
カスタムフックからAPIを呼び出す実装の際、つまずきポイントがいくつかあり大変だったので、忘れないように備忘録を残しましす。
前提条件
- React:18.2.0
- HackerNewsのAPIを使用
早速コード
useNews(カスタムフック)
import { useState, useEffect } from "react";
import { Article } from "../types";
export const useNews = (
url: string
): {
articles: Article[];
isLoading: boolean;
} => {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [articles, setArticles] = useState<Article[]>([]);
useEffect(() => {
const fetchNews = async () => {
try {
const res = await fetch(url);
const data = await res.json();
setArticles(data.hits);
setIsLoading(false);
} catch (error) {
setIsLoading(false);
}
};
fetchNews();
}, [url]);
return {
articles: articles,
isLoading: isLoading,
};
};
(呼び出し側)
import { useNews } from "../api/getNews";
export default function En() {
const url = `https://hn.algolia.com/api/v1/search?query=programing`;
const { articles, isLoading } = useNews(url);
if (isLoading) {
return <div>ローディング中</div>;
}
return (
<div>
{/* articlesを使ったなにか */}
</div>
);
}
つまずきポイント1
APIをasync/awaitで呼び出したいけど、カスタムフックuseNews
は同期的に呼びたい
(呼び出し側)
// useNewsにasyncを使えない
const { articles, isLoading } = useNews(url);
↓
カスタムフック内のuseEffectでasync/awaitを使う
useEffect(() => {
// useEffect「内」でAPI取得関数を定義する
const fetchNews = async () => {
try {
const res = await fetch(url);
const data = await res.json();
setArticles(data.hits);
setIsLoading(false);
} catch (error) {
setIsLoading(false);
}
};
// useEffect「内」でAPI取得関数を呼ぶ
fetchNews();
}, [url]);
つまずきポイント2
カスタムフックを更新できない
↓
useEffectの配列に更新されるstateを入れる
useEffect(() => {
// 略
}, [url]);//urlが更新したらカスタムフックが走る
まとめ
カスタムフックを再試行したいときはuseEffectを使おう
参考