TanStack Query入門
#React#TanStack Query
はじめに
- TanStack Query(旧React Query)は、非同期データの取得・キャッシュ・同期を簡単に行えるライブラリです
- useEffectとuseStateを使った従来のデータフェッチの複雑さを解消してくれます
- React以外にも、Vue、Solid、Svelteなど様々なフレームワークに対応しています
なぜTanStack Queryを使うのか
従来のデータフェッチの問題点
useEffectとuseStateを使った従来のパターンでは、多くのボイラープレートが必要です:
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
setIsLoading(true);
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => {
setUser(data);
setIsLoading(false);
})
.catch((err) => {
setError(err);
setIsLoading(false);
});
}, [userId]);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{user?.name}</div>;
}
このパターンには以下の問題があります:
- ローディング・エラー・データの3つの状態を手動で管理する必要がある
- キャッシュがないため、同じデータを何度もフェッチしてしまう
- コンポーネントがアンマウントされた後にstateを更新しようとする問題
- 複数のコンポーネントで同じデータを使う場合の共有が難しい
TanStack Queryで解決
TanStack Queryを使うと、上記のコードはこうなります:
function UserProfile({ userId }: { userId: string }) {
const {
data: user,
isLoading,
error,
} = useQuery({
queryKey: ["user", userId],
queryFn: () => fetch(`/api/users/${userId}`).then((res) => res.json()),
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{user?.name}</div>;
}
インストール
npm install @tanstack/react-query
セットアップ
アプリケーションのルートでQueryClientProviderを設定します:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
</QueryClientProvider>
);
}
基本的な使い方
useQuery - データの取得
useQueryはデータを取得するための基本的なフックです:
import { useQuery } from "@tanstack/react-query";
function TodoList() {
const { data, isLoading, error } = useQuery({
queryKey: ["todos"],
queryFn: async () => {
const response = await fetch("/api/todos");
return response.json();
},
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error occurred</div>;
return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
queryKeyについて
- queryKeyはクエリを一意に識別するためのキーです
- 配列形式で指定し、依存する値を含めることでキャッシュを適切に管理できます
- 例:
['todos']、['todo', todoId]、['todos', { status: 'done' }]
useMutation - データの更新
useMutationはデータの作成・更新・削除に使用します:
import { useMutation, useQueryClient } from "@tanstack/react-query";
function AddTodo() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newTodo: { title: string }) => {
return fetch("/api/todos", {
method: "POST",
body: JSON.stringify(newTodo),
});
},
onSuccess: () => {
// 成功時にtodosのキャッシュを無効化して再取得
queryClient.invalidateQueries({ queryKey: ["todos"] });
},
});
return (
<button onClick={() => mutation.mutate({ title: "New Todo" })} disabled={mutation.isPending}>
{mutation.isPending ? "Adding..." : "Add Todo"}
</button>
);
}
キャッシュの設定
TanStack Queryの強みはキャッシュ管理です。主要なオプションを紹介します:
const { data } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
staleTime: 1000 * 60 * 5, // 5分間はキャッシュを新鮮とみなす
gcTime: 1000 * 60 * 30, // 30分間キャッシュを保持(旧cacheTime)
});
- staleTime: データが「古い」とみなされるまでの時間。この間は再フェッチしない
- gcTime: 使われなくなったキャッシュがガベージコレクションされるまでの時間
DevToolsの活用
開発時にはDevToolsを使うとキャッシュの状態を可視化できます:
npm install @tanstack/react-query-devtools
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
まとめ
- TanStack Queryを使うことで、非同期データの取得・キャッシュ管理が大幅に簡単になります
- useQueryでデータ取得、useMutationでデータ更新を行います
- queryKeyを適切に設定することで、効率的なキャッシュ管理が可能です
- DevToolsを活用して、キャッシュの状態をデバッグできます