はじめに
今回は、ReactでAPIのfetchを簡単に行えるSWRを、もうちょっと便利に扱う自作メソッド等をご紹介します。
「もっとこんなやり方があるよ!」等の意見がありましたら是非コメントにお願いします!🙇🏻♂️🙇🏻♂️
本題
もっとも基礎的・シンプルなSWR
の使い方に、以下のようなコードがあります。
以下はユーザーのprofileデータをapiからfetchしてくるカスタムフックです。
const useProfile = () => {
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
};
const url = `${API_URL}/profile`;
const fetcher = async () => {
return axios.get(url, { headers }).then((response) => {
return response.data;
});
};
const { data, error, isLoading } = useSWR<Profile>(url, fetcher);
return { data, error, isLoading };
};
これでも十分にシンプルだとは思いますが、headers
やfetcher
に関しては使い回しがかなり効くので切り出してしまいましょう。
例えば以下はそれらを切り出してみた例です。
const swrFetcher = async (url: string) => {
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
};
const response = await axios.get(url, { headers });
return response.data;
};
const useProfile = () => {
const url = `${API_URL}/profile`;
const { data, error, isLoading } = useSWR<Profile>(url, swrFetcher);
return { data, error, isLoading };
};
こうしておけば、他のフックを作成する時にswrFetcher
をimportして使用するだけなので、書くのが多少楽になります。
また、SWR
にはデータの更新タイミング等を制御できる機能があります。
以下は、"初回のfetch以降、そのキャッシュを使い続ける"というoptionを付与したuseSWR
です。
(useSWRImmutable
という同等の機能を持つフックがありますが、説明のためuseSWR
を使用します)
const useProfile = () => {
const url = `${API_URL}/profile`;
const { data, error, isLoading } = useSWR<Profile>(
url,
swrFetcher,
{
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
}
);
return { data, error, isLoading };
};
この時第三引数部分を切り出しておくと、コードが簡潔になり同じオプションを他で使いたい時便利になります。
const swrConfig = {
// 初回のfetchのみ行い、以降はキャッシュを返すoption
Immutable: {
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnReconnect: false,
},
};
// 〜〜〜省略〜〜〜
const { data, error, isLoading } = useSWR<Profile>(
url,
swrFetcher,
swrConfig.Immutable
);
// 〜〜〜省略〜〜〜
コメントを書いておけばどういったオプションなのか一瞥しただけでわかりますし、こうすることで再利用しやすくなります。
大変ためになるコメントをいただいたので、以下その内容を追記させていただきます。
ここまでの内容をまとめると、コードは以下の状態です。
const swrFetcher = async (url: string) => {
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
};
const response = await axios.get(url, { headers });
return response.data;
};
const useProfile = () => {
const url = `${API_URL}/profile`;
const { data, error, isLoading } = useSWR<Profile>(
url,
swrFetcher,
swrConfig.Immutable
);
return { data, error, isLoading };
};
ここから更にコード量を減らし、楽に共通化できます。
axiosの機能にcreate
というものがあります。
これはインスタンスを作成するメソッドで、使用することによりbaseURL
やheaders
を変更したインスタンスを使用することができます。これを適用したコードは以下のようになります。
const instance = axios.create({
baseURL: 'http://localhost:3003/api', // 先程までのAPI_URLにあたる部分
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("token")}`,
},
});
const swrFetcher = async (url: string) => {
const response = await instance.get(url); // 上で作成したインスタンスを使用
return response.data;
};
const useProfile = () => {
const url = "profile";
const { data, error, isLoading } = useSWR<Profile>(
url,
swrFetcher,
swrConfig.Immutable
);
return { data, error, isLoading };
};
キーにも使用しているurlがかなりシンプルになり、swrFetcher
も二行で済むものになりました。
同じくaxiosの、interceptors
機能を使うことで同じような省略ができます。
これらは個人の好みや、やりたいことに対してどれだけ合っているかで選ぶ感じでしょうか。
おわりに
共通化できる部分はどんどん切り出していくとコードが見やすくなって良いんじゃないでしょうか🤗
SWRについて、またコードの書き方についてのコメント是非ともお願いします🙇🏻♂️
お読みいただきありがとうございました!