useEffectを使ったデータ取得から脱却し、高速化を図るイケてるライブラリであるよく似た2つ、”SWR”と”TanStack Query”を同じデータの取得を通し、違いの比較をしました。
この記事を見ていただくことで、両者の使い方の違いを知ることができます。
環境
- next @13.1.1
- swr @2.0.0
- tanstack/react-query @4.20.9
SWRとTanStack Queryをなぜ使うのか
両者の比較をする前に、なぜ使う必要があるのですが、それは使った方が良いからです。
以下の2つの使用メリットがあります。
- キャッシュからデータを返し(stale)、次にフェッチリクエストを送り(revalidate)、最後に最新のデータを持ってくるという処理を行ってくれるため、データの表示時間が短く早い上に、キャッシュを使用するため、余分なリクエストが飛ばないのでコストメリットもある。
- data と error と isLoading の値を使ってリクエストの現在の状態を判断し、 対応する UI を返すことができるから便利!
実行環境の用意
プロジェクトの作成・起動
% yarn create next-app swr-tanstackquery
% cd swr-tanstackquery
% yarn dev
axiosのinstall。これはデータの取得に使用します。
% yarn add axios
ルートのファイルであるpages/index.tsxのデフォルトの記述を削除します。
mainタグ内を全て消し、SWRとTanStackQueryの2つのcomponentを作ります。
import { Inter } from "@next/font/google";
import Head from "next/head";
import SWRFetch from "../components/swr-fetch";
import TanStackQueryFetch from "../components/tanstack-query-fetch";
const inter = Inter({ subsets: ["latin"] });
export default function Home() {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<SWRFetch />
<TanStackQueryFetch />
</main>
</>
);
}
これで、実際にコードを書いていくためのベースができました。
SWR
% yarn add swr
SWRFetch componentを作成します。
import useSWR from "swr";
import axios from "axios";
type Album = {
userId: number;
id: number;
title: string;
};
// jsonplaceholderよりデータを取得
const fetchAlbums = async () => {
const result = await axios.get<Album[]>(
"https://jsonplaceholder.typicode.com/albums"
);
return result.data;
};
const SWRFetch = () => {
const { data, error, isLoading } = useSWR("/api/album", fetchAlbums);
if (error) return <p>An error has occurred</p>;
if (isLoading) return <p>Loading...</p>;
return (
<div>
<p>SWR</p>
{data?.map((album) => (
<p key={album.id}>{album.title}</p>
))}
</div>
);
};
export default SWRFetch;
useSWRの第一引数である”/api/album”は、一意な識別子であり、第二引数の関数に渡されるものです。
TanStack Query
% yarn add @tanstack/react-query
componentの親側とcomponent内の両方に設定を行います。
import { Inter } from "@next/font/google";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import Head from "next/head";
import SWRFetch from "../components/swr-fetch";
import TanStackQueryFetch from "../components/tanstack-query-fetch";
const inter = Inter({ subsets: ["latin"] });
// Create a client
const queryClient = new QueryClient();
export default function Home() {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<SWRFetch />
{/* Provide the client */}
<QueryClientProvider client={queryClient}>
<TanStackQueryFetch />
</QueryClientProvider>
</main>
</>
);
}
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
type Album = {
userId: number;
id: number;
title: string;
};
// jsonplaceholderよりデータを取得
const fetchAlbums = async () => {
const result = await axios.get<Album[]>(
"https://jsonplaceholder.typicode.com/albums"
);
return result.data;
};
const TanStackQueryFetch = () => {
const { isLoading, error, data } = useQuery<Album[]>({
queryKey: ["album"],
queryFn: fetchAlbums,
});
if (error) return <p>An error has occurred</p>;
if (isLoading) return <p>Loading...</p>;
return (
<div>
<p>TanStack Query</p>
{data?.map((album) => (
<p key={album.id}>{album.title}</p>
))}
</div>
);
};
export default TanStackQueryFetch;
まとめ
両者の記述方法は、ほとんど同じです。
TanStack Queryのcomponentの親側にも設定記述が必要なことから、やや記述量が多いですが、働き、記述ともにほとんど差がないことがわかりました。
今回取り上げたSWR、TanStack Queryは、ReactのhooksであるSuspenseを使っても一部代替可能です。
それについては以下記事にまとめていますのでご覧ください。
以上、お読みいただきありがとうございました。
コメント