プログラミング フレームワーク ソフトウェア 公開日 2026.05.15 更新日 2026.05.20

TanStack Query(旧 React Query)とは何か?非同期データ取得とキャッシュの標準ライブラリ

TanStack Query(旧 React Query)は、「サーバから取ったデータをキャッシュし、適切に同期する」 ためのライブラリで、React / Solid / Vue / Svelte で使えます。「useState + useEffect + fetch」 で苦労していた多くの場面を 「useQuery」 1行で置き換えられる、現代フロントエンドのデファクトです。

先に要点

  • TanStack Query(旧 React Query)は、「サーバから取ったデータ(server state)」 を扱う専用ライブラリ。「useState + useEffect + fetch + ローディング + エラー + 再取得」 を毎回書く苦痛を 「 useQuery」 1行 で解消する。
  • 核は 「 stale-while-revalidate」 のキャッシュ戦略。「古いキャッシュをまず表示 → バックグラウンドで新しいデータを取り直す → 変わっていれば更新」 という挙動を、デフォルトで提供する。
  • 提供機能は広い: キャッシュ管理 / 再試行 / 自動再取得(focus / online)/ ページネーション / 無限スクロール / 楽観的更新 / プリフェッチ / DevTools。「データ取得まわりの定番ハマりどころ」 が一通り入っている。
  • React 専用ではない。「 Solid / Vue / Svelte / Angular」 でも同じ概念で使えるtRPCHono RPC の標準クライアントとしても採用されている。

React Query ってよく聞くけど、Redux とどう違うの? 「useEffect で fetch するのと何が違うの?」 「今は TanStack Query って名前変わった?」 ── 2018年頃から急速に広まった React Query は、2022年に TanStack Query へ改名し、現在はマルチフレームワーク対応の 「サーバ状態ライブラリ」 として定着しました。

ざっくり言うと、TanStack Query は サーバから取ったデータをキャッシュして、必要なときに同期する 専門ライブラリです。 「サーバ状態(server state)」 を扱うことに特化していて、「クライアント側だけの状態(UI 状態など)」 とは別物として扱う、というのが設計思想の核心です。

この記事では、2026年5月時点の TanStack Query v5 系をベースに、仕組み・基本の書き方・Redux 等との違い・採用判断軸 を整理します。 仕様は活発に変化しているので、最終確認は 公式ドキュメント を見るのが安全です。

なぜ TanStack Query が必要になったか

「なぜわざわざ専用ライブラリが必要なのか」 を 「useState + useEffect」 と比較すると分かりやすくなります。

// 「素朴な」 書き方
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    setLoading(true);
    fetch(`/api/users/${userId}`)
      .then(r => r.json())
      .then(setUser)
      .catch(setError)
      .finally(() => setLoading(false));
  }, [userId]);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error</p>;
  return <p>{user.name}</p>;
}

これに対して、TanStack Query では:

import { useQuery } from '@tanstack/react-query';

function UserProfile({ userId }) {
  const { data: user, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetch(`/api/users/${userId}`).then(r => r.json()),
  });

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error</p>;
  return <p>{user.name}</p>;
}

行数の差以上の違い

素朴な書き方では 別画面に行って戻ると毎回再取得」 「タブを切り替えるたびに再フェッチ」 「エラーで自動再試行する」 などが手動 / 未対応。TanStack Query はこれらをデフォルトで適切に処理する。

キャッシュの共有

` 同じ 「queryKey」 を別コンポーネントで使うと、自動で同じキャッシュを参照する」 → 同じデータが2回フェッチされる無駄が消える。

再取得のタイミング

「 ウィンドウフォーカス時」 「ネットワーク再接続時」 「mount 時」 など、「いつ取り直すか」 を細かく設定できる。「画面を放置していたら古いデータが表示されたまま」 が起きづらい。

エラー / リトライ

「 失敗したら指数バックオフで自動リトライ」 が標準。「ネットワークの一瞬の不調」 で諦めない。

「非同期の細かい挙動を毎回手書きしなくていい」 のが、TanStack Query の最大の利点です。

キャッシュの考え方 — stale と fresh

TanStack Query のキャッシュは、stale-while-revalidate という考え方に基づいています。

「fresh」 状態

取ったデータが 「まだ新しい」 とみなされる期間。「staleTime」 で指定。デフォルトは 0 ms(取った瞬間に古くなる扱い)。

「stale」 状態

「 まだキャッシュには残っているが、新しい値を取りに行ってもいい」 状態。表示は即時、裏側でリフェッチ。

「cacheTime」 / 「gcTime」

「 どのコンポーネントからも使われなくなった後、何分間キャッシュを保持するか」。デフォルトは 5分

refetch のトリガ

「stale なときに mount / window focus / network reconnect」 で自動再取得。「そんなに頻繁にいらない」 場合は 「staleTime」 を伸ばす。

`データを 「絶対今の値」 か 「だいたい近い値」 のどちらで扱うか」 を 「staleTime」 でチームごとに調整するのが、TanStack Query の運用の中心です。

主要機能の一覧

「データ取得まわりの定番タスク」 が一通りそろっています。

機能 API 用途
取得 「useQuery」 GET 系。データを読む。
更新 「useMutation」 POST / PUT / DELETE 系。書き込み。
無効化 「queryClient.invalidateQueries」 「 この queryKey のキャッシュを古い扱いにする」。
楽観的更新 「onMutate / setQueryData / onError」 サーバ応答前に UI を仮更新。
無限スクロール 「useInfiniteQuery」 ページネーション + 「次へ」 を自動管理。
プリフェッチ 「queryClient.prefetchQuery」 「 次の画面に行く前に先取り」。
サスペンス連携 「useSuspenseQuery」 React Suspense と組み合わせる。
DevTools 「@tanstack/react-query-devtools」 キャッシュ状態を視覚化。

「データ取得で手で書きたくない処理は、まず TanStack Query にあるか確認する」 だけで、ほぼ何でも見つかる印象です。

Redux / Zustand / Context との違い

「なんで状態管理ライブラリの代わりに使うの?」 という疑問は、よく出ます。

Redux / Zustand / Context TanStack Query
得意領域 クライアント状態(UI 状態、フォーム、モーダル) サーバ状態(API から取ったデータ)
キャッシュ 自前で実装 標準で提供
非同期 middleware や thunk で手書き 標準で提供
再取得 / 同期 手書き 標準で提供
主な責務 「 クライアントが持つべき状態」 「 サーバが真実とする状態のキャッシュ」
組み合わせ TanStack Query と併用がベスト Redux / Zustand と併用がベスト

要点は Redux 系と TanStack Query は競合ではなく、役割分担で併用する ことです。 「サーバから取ったデータは TanStack Query、UI 状態(ダークモード / モーダル開閉)は Zustand / Context」 という棲み分けが2026 年現在の主流です。

楽観的更新の書き方

UX を高める典型機能 「楽観的更新」 の書き方を見ます。

const queryClient = useQueryClient();

const toggleLike = useMutation({
  mutationFn: (postId) =>
    fetch(`/api/posts/${postId}/like`, { method: 'POST' }),

  onMutate: async (postId) => {
    // 進行中の取得をキャンセル
    await queryClient.cancelQueries({ queryKey: ['posts'] });

    // 前の値を保持(ロールバック用)
    const previous = queryClient.getQueryData(['posts']);

    // 楽観的に更新
    queryClient.setQueryData(['posts'], (old) =>
      old.map(p => p.id === postId ? { ...p, liked: !p.liked } : p)
    );

    return { previous };
  },

  onError: (err, postId, context) => {
    // 失敗したら前の値に戻す
    queryClient.setQueryData(['posts'], context.previous);
  },

  onSettled: () => {
    queryClient.invalidateQueries({ queryKey: ['posts'] });
  },
});

楽観的更新とは

「 サーバ応答を待たずに、UI を先に更新する」 こと。ボタンを押したら即色が変わる、いいねが即反映する、といった 「早く感じる UX」 を実現する。

ロールバック

失敗時に 「前の値に戻す」 ロジックが必須。TanStack Query の 「onMutate → onError」 パターンで自然に書ける。

最終的な同期

「onSettled」 で 関連キャッシュを invalidate して、最終的にはサーバの値で上書きされるようにする。

React 19 との関係

React 19 の 「useOptimistic」 は Server Actions と組み合わせて使う仕組み。「TanStack Query で全部完結する」 ケースと 「React 標準の useOptimistic を使う」 ケースが棲み分かれつつある。

`非同期処理の 「応答までの空白」 をなくす」 のが楽観的更新の核心で、TanStack Query はこれを正攻法で書きやすくしてくれます。

いつ TanStack Query を使うか

採用判断の目安を整理します。

向いている

React / Solid / Vue / Svelte の中〜大規模アプリ、② 複数画面で同じデータを表示する SPA、③ 非同期取得が多い管理画面 / SaaS、④ tRPC / GraphQL Code Generator の組み合わせ。

慎重に

① 純粋に App Router + RSC + Server Actions だけで完結する小規模アプリ(「useQuery が要らない」 ケースが増える)、② 「1ページだけ」 のような極小プロジェクト、③ サーバ側で全部レンダリング前提のサイト。

RSC / Server Actions との関係

「 データ取得の主役を RSC に寄せる」 場合、TanStack Query の必要性は下がる。ただし、「クライアント側のリアルタイム更新」 「フォーカス時の再取得」 が必要な場面では、依然として有力。

tRPC との相性

tRPC の React 統合は TanStack Query をベースに作られている。「tRPC を使う = TanStack Query もセットで使う」 と言って差し支えない。

「React 系のフルスタックアプリ」 を作るなら、いまも 「必須スキル」 に近い位置にいます。

ハマりやすいポイント

便利な反面、現場で踏みやすい注意点も整理します。

①「queryKey」 設計

「 queryKey が同じだとキャッシュを共有する」 ので、「配列の構造」 を最初に決めておく。「 ['posts', { userId, page }]」 のような構造 がチーム標準的。

② staleTime デフォルト 0

「 取った瞬間 stale 扱い」 になり、毎回 refetch がトリガーされやすい。「staleTime: 1000 * 60」 などを 「defaultOptions」 で設定すると、無駄な再取得が減る。

③ 無効化漏れ

「 更新したのにリストが古いまま」 が起きやすい。「useMutation の onSuccess で invalidateQueries」 を必ず入れる。

④ DevTools を入れていない

「 どのキャッシュが今 stale で、どれが fresh か」 を視覚化できる DevTools が必須レベルに便利。開発時は必ず入れる。

「設定の妥当性を体感で詰める」 のが、TanStack Query の運用を綺麗にする最大のコツです。

AI 時代の TanStack Query

AI 連携の文脈でも TanStack Query は活躍します。

AI 応答のストリーミング

「 useQuery で AI レスポンスを取りつつ、ストリーミングは別途処理」 のような構成が組める。「生成中の状態 + 過去履歴の表示」 を統一的に扱える。

プリフェッチで体感速度向上

「 次に必要そうな AI 応答」 をプリフェッチしておくことで、「クリック後の待ち時間」 を実質ゼロにできる。AI のレスポンス遅さを UX 上隠せる。

楽観的更新 × AI

「 AI チャットで送信 → 即ユーザーメッセージを表示 → AI 応答が返ったら追加」 という典型的な UX を、「useMutation + 楽観的更新」 で素直に書ける。

tRPC + TanStack Query + AI

「 AI 呼び出しを tRPC mutation として定義 → TanStack Query 統合で再取得 / 楽観的更新」 という構成は、AI 機能を持つアプリの定番パターン。

「AI 応答の不確実な遅延」 を 「TanStack Query のキャッシュとプリフェッチ」 で吸収する、というのは AI 時代の UX 設計で頻出するパターンです。

TanStack Query に関するよくある質問

Q. React Query と TanStack Query は同じものですか?

A. 同じです。2022 年に 「React Query」 から 「TanStack Query」 に改名し、React 以外のフレームワーク(Solid / Vue / Svelte / Angular)もサポートする多目的ライブラリになりました。「React Query」 は React 向けアダプタの呼称として残っています。

Q. SWR と TanStack Query、どちらを選ぶべきですか?

A. 用途と好みで分けます。SWR は Vercel 製の軽量・シンプル路線TanStack Query は機能が豊富で 「何でもできる」 路線。「小さなアプリで軽さ重視」 なら SWR、「本格的な機能と DevTools が欲しい」 なら TanStack Query、というのがざっくりの選び方です。

Q. RSC と Server Actions だけで完結する場合、TanStack Query は不要ですか?

A. ケースバイケースです。完全に 「読みは RSC、書きは Server Actions、再取得は revalidatePath」 で済む場合は不要です。ただし、「Realtime な再取得」 「フォーカス再取得」 「楽観的更新」 が必要な場面では、TanStack Query を併用する設計が依然として有効です。

Q. tRPC と TanStack Query は必ずセットですか?

A. React で tRPC を使う場合は事実上セットです。「tRPC の React Hooks」 は内部的に TanStack Query を使っており、「useQuery / useMutation」 と同じ感覚で 「trpc.x.useQuery()」 が使えます。

Q. キャッシュ無効化を全部書くのが面倒です。

A. queryKey の階層を意識して、まとめて invalidate するのが定石です。「queryClient.invalidateQueries({ queryKey: ['posts'] })」 だけで 「['posts', ...]」 系すべてのクエリを無効化できます。

Q. SSR ではどう使いますか?

A. サーバ側でデータをフェッチ → dehydrate してクライアントに渡す → hydrateのパターンが基本です。Next.js / Remix での専用ヘルパー(「HydrationBoundary」 等)があります。

Q. TanStack Query を学ぶ最短ルートは?

A. ① 「useQuery」 で1つ取得、② 「useMutation」 で1つ更新、③ 「queryClient.invalidateQueries」 で再取得、④ DevTools をインストールして挙動を観察、の4段階が王道です。「動かしながらキャッシュ状態を見る」 のが、TanStack Query の理解を加速する最大のコツです。

参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。