参考対象
- useSWRって何?という方
- データ取得にuseEffectを使用している方
インフォメーション
こちらは初歩的な内容になっております。もっと知りたい方は公式ドキュメント等をご覧ください。
useSWRとは
公式ドキュメントから引用します。
“SWR” という名前は、 HTTP RFC 5861(opens in a new tab) で提唱された HTTP キャッシュ無効化戦略である stale-while-revalidate に由来しています。 SWR は、まずキャッシュからデータを返し(stale)、次にフェッチリクエストを送り(revalidate)、最後に最新のデータを持ってくるという戦略です。
つまり、useSWRは特定のデータをキャッシュし、必要に応じてそのデータを返しつつ、バックグラウンドで新しいデータを取得して最新状態を保ちます。
useEffectでデータをフェッチする方法
まずは、useEffectを使ったデータ取得方法を見てみましょう。今回のサンプルコードでは、JSONPlaceholderからユーザーデータを取得し、一覧を表示します。
import axios from "axios";
import { useEffect, useState } from "react";
interface User {
id: string;
username: string;
email: string;
address: {
city: string;
};
}
const api = "https://jsonplaceholder.typicode.com/users";
function App() {
const [users, setUsers] = useState<User[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
setIsLoading(true);
setError(null);
const getUser = async () => {
try {
const response = await axios.get(api);
setUsers(response.data);
} catch (err) {
setError("Failed to fetch users.");
console.error(err);
} finally {
setIsLoading(false);
}
};
getUser();
}, []);
if (error) return <div>{error}</div>;
if (isLoading) return <div>Loading...</div>;
return (
<div className="App">
<ul>
{users.map((user) => (
<li key={user.id}>
<p>{user.username}</p>
<p>{user.email}</p>
<p>{user.address.city}</p>
</li>
))}
</ul>
</div>
);
}
export default App
このコードでは、useEffect内でAPIを叩いています。useEffectの第二引数を空配列にしているので、初回マウント時のみ発火します。
コードを見ると、ユーザー情報、ローディング状態、エラー状態を管理するためにuseStateが多く使われています。また、useEffectにはキャッシュのメカニズムがないため、データに変更がない場合でもリロードするたびにデータ取得を行っています。
これらの問題を解決してくれるのが、useSWRです!
useSWRでデータをフェッチする方法
次に、useSWRを使ったデータ取得方法を見てみましょう。
useSWRのデータの取得方法は以下のようになります。(公式ドキュメント参照)
import useSWR from 'swr'
import axios from 'axios'
// fetchを使用した場合
const fetcher = url => fetch(url).then(r => r.json()) // urlはuseSWR()の第一引数で渡されたURL
// axiosを使用した場合
const fetcher = url => axios.get(url).then(res => res.data)
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
useSWRフックはキー文字列とフェッチ関数を受け取ります。キーはデータの一意な識別子(通常はAPIのURL)で、フェッチ関数に渡されます。フェッチ関数はデータを返す非同期関数で、ネイティブのfetchやAxiosのようなツールを使用できます。
このフックは、リクエストの状態にもとづいて data と isLoading, error の三つの値を返します。
useSWRを使用する利点は以下の通りです。
- キャッシュにより、同じデータを何度も取得する必要がなく、アプリケーションのレスポンス性能が向上。
- デフォルトでデータを自動的に再取得する仕組みを持っているため、データが変更された際に自動的に最新の情報を反映可能。
- 少ないコードで効果的にデータを取得できる。
では、実際にuseSWRを使用してユーザー情報を取得してみましょう!
import { useFetchUser } from './hooks/useFetchUser'
function App() {
const { data, error, loading } = useFetchUser();
if (error) {
console.error(error);
return (
<div>Failed to fetch users.</div>
)
};
if (loading) return <div>Loading...</div>
return (
<div>
<ul>
{data?.map((user) => (
<li key={user.id}>
<p>{user.username}</p>
<p>{user.email}</p>
<p>{user.address.city}</p>
</li>
))}
</ul>
</div>
)
}
export default App
import axios from "axios";
import useSWR from "swr";
import { User } from "../type/type";
const fetcher = (url :string) => axios.get(url).then((res) => res.data);
const api = "https://jsonplaceholder.typicode.com/users"
export const useFetchUser = () => {
const { data, error, isLoading } = useSWR<User[]>(api, fetcher);
return {
data,
error,
loading: isLoading,
}
}
export interface User {
id: number;
username: string;
email: string;
address: {
city: string;
};
}
useFetchUserというフックを作成し、そこでAPIを叩いています。取得したdata、error、loadingを返却します。
App.tsxでuseFetchUserからdata、error、loadingを受け取り、エラー時、ローディング時、成功時の処理をしています。
...めっちゃ簡単!記述が凄いシンプルになりました!ステートでの管理がなくなったのでコードも見やすくなりました。
まとめ
今まで「APIを叩く→useEffectを使う!!!」という考えでしたが、これを機にuseSWRを積極的に使ってみようと思います。
間違ってる点などございましたら、ぜひコメントで教えてください。