TanStack Query って、どんな機能があるのかな?
今回は、React.js で APIからのデータ取得 をシンプルにしてくれるライブラリ TanStack Query(旧 React Query) について、基本的な考え方から実際の使い方、さらに Redux Toolkit と組み合わせた実践的なユースケース までをわかりやすく解説します。
※ React.js の環境構築がまだお済みでない場合は、下記より環境構築を行なってください。
TanStack Query(旧 React Query) とは?
TanStack Query(旧 React Query) とは、サーバーから取得したデータ(サーバーステート)を管理するための React.js ライブラリ のことで、API からデータを取得する ときに発生しがちな 読み込み中の表示 や エラー時の処理、最新データの取得 といった処理を 自動で行ってくれます。
そのため、useEffect や useState を使った複雑なコードを書かなくても、少ないコードで直感的かつ安全にデータ取得の処理を実装することができます。
TanStack Query のメリット
- ローディング・エラー管理が簡単
データ取得に必要な状態はすべて自動で管理されます。 - キャッシュによる高速化
一度取得したデータはキャッシュされるため、同じデータを使う画面では不要なAPI通信を減らせます。 - 常に最新のデータを保てる
画面の再表示やネットワーク復帰時など、適切なタイミングで自動的にデータを再取得してくれます。
TanStack Query のインストールと基本的な使い方
それでは、ここから実際に TanStack Query を インストール したり、コンポーネントで利用する 基本的な流れを見ていきましょう。
TanStack Query のインストール
TanStack Query を インストール します
npm install @tanstack/react-query
TanStack Query 基本的な使い方
QueryClientProvider
TanStack Query を使うには、アプリ全体で QueryClient を設定する必要があります。
QueryClient は データ取得の設定やキャッシュを管理するためのオブジェクト のことで、 QueryClientProvider を使用することで、作成した QueryClient をアプリ全体にデータを提供することができます。
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.jsx';
import { Provider } from 'react-redux';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
createRoot(document.getElementById('root')).render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</StrictMode>,
);
useQuery
useQuery を使うことで、APIからデータを取得する処理と状態管理 を一度に行うことができます。
// { data: '取得したデータ', isLoading: 'データ取得中の有無', isError: 'エラーが発生の有無', error: 'エラーの内容' } =
// useQuery(queryKey: '取得したいデータの名前', queryFn: 'データの取得方法')
const { data, isLoading, isError, error } = useQuery({
queryKey: ["key"],
queryFn: fetcher,
});
useMutation
useMutation は サーバーにデータを送る処理(POST / PUT / DELETEなど) を行うためのフックです。
// { data: '取得したデータ', isLoading: 'データ取得中の有無', isError: 'エラーが発生の有無', error: 'エラーの内容' } =
// useMutation(mutationFn: 'データの送信処理', onSuccess: '成功時の処理', onError: '失敗時の処理', onSettled: '成功・失敗どちらでも実行される処理')
const mutation = useMutation({
mutationFn: fetcher,
onSuccess: () => {
// 成功時の処理: 成功メッセージ表示、UI更新
},
onError: (error) => {
// 失敗時の処理: エラーメッセージ表示
},
onSettled: () => {
// 成功・失敗どちらでも実行される処理
// 共通の後処理 ローディング解除、フォームリセット、Query再取得
},
});
invalidateQueries
invalidateQueries は 指定した queryKey に対応する Query を 再取得 します。
その結果、 useQuery が持っている キャッシュ が 最新のサーバーデータで更新 され、その useQuery が使用している コンポーネントも再レンダリング され、最新データが画面に反映 されます。
// queryKey の Query を再取得して、最新データにキャッシュを更新し、コンポーネントも再レンダリングされる
queryClient.invalidateQueries(["queryKey"]);
コード例
テスト用のAPI の為、「data.push({ id: data.length + 1, name });」で、ユーザーデータを手動で追加して、ユーザー一覧情報に表示
※通常は、「queryClient.invalidateQueries([‘users’]);」でコードのみで、キャッシュの更新とデータの再取得を自動で行ってくれる
import { useState } from 'react';
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
// ユーザー一覧情報の取得処理
async function fetchUsers() {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
if (!res.ok) throw new Error('Failed to fetch users');
return res.json();
}
// 新しいユーザーを追加処理
async function addUser(newUser) {
const res = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newUser),
});
if (!res.ok) throw new Error('Failed to add user');
return res.json();
}
export default function TanStackQueryUsers() {
const queryClient = useQueryClient();
const [name, setName] = useState('');
// サーバーデータ取得
const { data, isLoading, isError, error } = useQuery({
queryKey: ['users'],
queryFn: fetchUsers,
});
// データ更新用
const mutation = useMutation({
mutationFn: addUser,
onSuccess: (res) => {
console.log('res:', res);
// 更新後にユーザー一覧を再取得
// テスト用のAPIの為、データを再取得してもデータが更新されない為、コメントアウト
// queryClient.invalidateQueries(['users']);
// テスト用の為、ユーザーデータを手動で追加して、ユーザー一覧情報に表示
data.push({ id: data.length + 1, name });
},
onSettled: () => {
setName(''); // 入力値を初期化
},
});
// ローディング(データ取得)中の場合
if (isLoading) return <p>Loading...</p>;
// エラー時の場合
if (isError) return <p>Error: {error?.message}</p>;
return (
<>
<h2>TanStack Query Users</h2>
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="New user name"
/>
<button
onClick={() => {
mutation.mutate({ name });
}}
>
Add User
</button>
</>
);
}
処理内容
- 画面をリロード(更新処理)
- 一瞬 “Loading…” の文字が表示され、複数のユーザー名がリスト表示 される
- 入力欄に”テストユーザー“と入力して、”Add User”ボタンをクリックする
- 複数のユーザー名がリスト表示 に”テストユーザー“が追加され、ログにも”テストユーザー“が表示される

TanStack Query + Redux Toolkit と連携したユースケース
TanStack Query + Redux Toolkit の構成
役割分担
TanStack Query と Redux Toolkit を組み合わせる場合は、それぞれの役割を明確に分けることが重要です。
- TanStack Query
サーバー からの データ取得やキャッシュ管理、データの自動更新処理を管理 し、常に最新のデータ を扱います。 - Redux Toolkit
アプリ全体で共有 したい ログイン情報 や、選択中のデータなどのクライアントの状態を管理します。 - useMutation
TanStack Query が 保持しているキャッシュを最新の状態に更新するためにPOST/PUT/DELETE などに使用します。
Redux Toolkit の状態 と サーバーのデータを同期させたい場合 にも 重要な役割 を持ちます。
メリット
この構成の メリット として、データ更新時の流れが次のように整理されます。
- API を呼び出してサーバー側のデータを更新 する
- useMutation
()を使って TanStack Query のキャッシュを更新し、画面を即座に最新化 する - Redux Toolkit に dispatch して、アプリ全体の状態を更新 する
このように、「サーバー更新 → 画面更新 → Redux Toolkit 共有」という流れが明確になるため、状態管理 が複雑になりにくく、安全に実装できます。
TanStack Query + Redux Toolkit のコード例
Redux Toolkit について
Redux Toolkit について、下記の記事でも詳しく紹介している為、参考にしてみてください。
Slice の作成
ユーザー の 状態(データ)の初期値 や 処理内容 を登録する
import { createSlice } from '@reduxjs/toolkit';
const initialState = { value: 0 };
const tsqCounterSlice = createSlice({
name: 'tsqCounter',
initialState,
reducers: {
increment(state) {
state.value += 1;
},
decrement(state) {
state.value -= 1;
},
},
});
export const { increment, decrement } = tsqCounterSlice.actions;
export default tsqCounterSlice.reducer;
Store に Slice の登録・追加
上記の Slice を呼び出せるように、Store に登録する
// store.js
import { configureStore } from '@reduxjs/toolkit';
import tsqCounterReducer from './tsqCounterSlice';
export const store = configureStore({
reducer: {
tsqCounter: tsqCounterReducer,
},
});
Provider の設定
上記の Store を アプリ上 で 状態管理 ができるように、QueryClient を囲むように Provider を設定する
// main.jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App.jsx';
import { Provider } from 'react-redux';
import { store } from './store';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
createRoot(document.getElementById('root')).render(
<StrictMode>
<Provider store={store}>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</Provider>
</StrictMode>
);
データの取得・表示・更新
アプリ上 で、状態(データ)の取得・表示・更新 を確認する
// App.js
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './tsqCounterSlice';
import TanStackQueryUsers from './TanStackQueryUsers';
function App() {
const count = useSelector((state) => state.tsqCounter.value);
const dispatch = useDispatch();
return (
<>
<h1>TanStack Query + useMutation + Redux Toolkit</h1>
{/* TanStack Query 基本的な使い方 で作成した処理 */}
<TanStackQueryUsers />
<div>
<h2>Counter: {count}</h2>
<button onClick={() => dispatch(increment())}>+</button>
<button onClick={() => dispatch(decrement())}>-</button>
</div>
</>
);
}
export default App;
処理内容
- “画面をリロード(更新処理)
- 一瞬 “Loading…” の文字が表示され、複数のユーザー名がリスト表示 される
- 入力欄に”テストユーザー“と入力して、”Add User”ボタンをクリックする
- 複数のユーザー名がリスト表示 に”test user“が追加され、ログにも”test user“が表示される
- “+” ボタンをクリックし、”Counter” が “+1” ずつ カウントアップ される
- “–” ボタンをクリックし、”Counter” が “-1” ずつ カウントダウン される

まとめ
TanStack Query(旧 React Query) について、useMutation や Redux Toolkit とあわせて解説してきましたが、いかがでしたでしょうか?
TanStack Query は サーバーから取得したデータ(サーバーステート)を管理するための React.js ライブラリ のことで、API からの データ取得やキャッシュ管理、データの自動更新といった処理を管理 し、常に最新のデータ を扱えるようにしてくれます。
また サーバーデータを更新するために使用する useMutation(POST/PUT/DELETE など) や アプリ全体で共有 したい ログイン情報 や 選択中のデータなどの状態を管理 してくれる Redux Toolkit を組み合わせることで、「サーバー更新 → 画面更新 → Redux Toolkit での共有」 という流れが明確になり、状態管理 が複雑になりにくく、安心して実装を進めることができます。
まずは TanStack Query の基本的な使い方をしっかり押さえ、小さな コンポーネント で試しながら、少しずつ useMutation や Redux Toolkit を組み合わせて使えるようになっていきましょう。
公式サイト






コメント