tech-book-labs
データユーティリティ · 最終検証 2026-09-01 · @tanstack/react-query 5.102.8 · 初公開 2026-09-01

TanStack Query v5 でサーバー状態を管理する

TanStack Query v5(旧 React Query)の最小構成とキャッシュの動き。status と fetchStatus の 2 軸、staleTime / gcTime の役割分担、同一 queryKey の重複排除、invalidateQueries の挙動、v4 からの破壊的変更(cacheTime 廃止・単一オブジェクト引数)を、動く demo と実測で確認する。

tanstack-query react-query cache react data-fetching

検証日: 2026-09-01

使用バージョン: @tanstack/react-query@5.102.8(React 19)

対象: fetch + useState でのデータ取得管理に限界を感じている / v4 の記事のコードが v5 で動かない場面

TanStack Query v5(旧 React Query)で サーバー状態(サーバーから取ってきたデータのローカルコピー)を管理する最小構成。キャッシュがいつ「新鮮」でいつ「再取得」されるかを、動く demo と実測ログで確認します。

触って試す

コンポーネント A / B は同じ queryKey を独立に useQuery している。それでも疑似 API の呼び出しは 1 回 — これが TanStack Query の中核で、「どのコンポーネントがデータを持つか」を設計しなくてよくなる。

なぜ TanStack Query か

useEffect + useState の自前 fetch 管理と比べて、次が最初から付いてくる:

  • キャッシュと重複排除: 同じ queryKey の取得は 1 本にまとまる(demo の A / B)
  • stale-while-revalidate(古いデータを見せつつ裏で再取得): 再取得中も前のデータが表示され続ける
  • リトライ・エラー状態・ローディング状態の一貫した表現

グローバル状態ライブラリ(Redux 等)の代替ではなく、「サーバー由来のデータ」専用のレイヤー。フォーム入力のようなクライアント状態には使わない。

最小サンプル(Provider + useQuery)

npm i @tanstack/react-query
項目
検証バージョン@tanstack/react-query@5.102.8
peer 要件React 18 / 19
TypeScript 型本体同梱
v5 の要求環境ES2020(古いブラウザサポートは v4 まで)

アプリのルートに QueryClientProvider を置き、コンポーネントで useQuery を呼ぶ:

import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";

const client = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={client}>
      <User />
    </QueryClientProvider>
  );
}

function User() {
  const { data, isPending, isError, error } = useQuery({
    queryKey: ["user", 1],           // キャッシュの識別子(配列)
    queryFn: () => fetch("/api/users/1").then((r) => r.json()),
  });
  if (isPending) return <p>読み込み中…</p>;
  if (isError) return <p>エラー: {error.message}</p>;
  return <p>{data.name}</p>;
}

status と fetchStatus は別の軸

v5 の状態は 2 軸で読む。status は「データがあるか」、fetchStatus は「いま通信しているか」。実測した遷移:

タイミングstatusfetchStatusisPendingisLoading
初回 mount 直後pendingfetchingtruetrue
初回成功後successidlefalsefalse
refetch 中(データあり)successfetchingfalsefalse
  • isPending = データがまだ無い(status === "pending")
  • isLoading = isPending && isFetching — つまり「初回だけの読み込み中」
  • refetch 中は isLoading にならない(前のデータを表示したまま裏で更新される)

「スピナーを出すのは初回だけ、更新中は今のデータを見せる」が、この 2 軸を使い分けるだけで書ける。

staleTime と gcTime(旧 cacheTime)

キャッシュの寿命を決める 2 つの時間は役割が違う:

オプション意味既定値
staleTimeこの時間内は「新鮮」= マウント時・フォーカス時の自動再取得をしない0(即 stale)
gcTime使っているコンポーネントが 1 つも無くなってから、キャッシュを捨てるまでの時間5 分

gcTime の動きを query-core で実測したログ(gcTime を 100ms に設定):

unsubscribe 直後 cache: "data"        ← アンマウント後もすぐには消えない
gcTime(100ms) 経過後 cache: undefined ← 経過後に GC される

invalidateQueries — 更新後の再取得

ミューテーション(データ更新)の後にキャッシュを更新する基本形が invalidateQueries。実測では staleTime: Infinity でも、アクティブな query は即座に再取得された:

const qc = useQueryClient();

await updateUser(form);                          // サーバーを更新して
qc.invalidateQueries({ queryKey: ["user"] });    // 関連キャッシュを無効化 → 自動再取得

queryKey は前方一致で効くので、["user"] を invalidate すると ["user", 1] / ["user", 2] もまとめて対象になる。

リトライの既定値はブラウザとサーバーで違う

失敗時の自動リトライは既定 3 回(計 4 回試行)— ただしこれはブラウザでの話。Node(SSR)で実行すると リトライ 0 回で即 error になる(実測: 試行 1 回で status: "error")。SSR とブラウザで「エラーの出やすさ」が変わるので、テストやサーバープリフェッチでは retry を明示するのが安全:

useQuery({ queryKey, queryFn, retry: 1 });  // 環境差を無くしたいとき

つまずいたポイント

  • v4 の複数引数 useQuery(key, fn) が型エラー — v5 は単一オブジェクトのみ。機械的に useQuery({ queryKey, queryFn }) へ書き換える
  • cacheTime が黙って無視される — v5 では gcTime。JS だと警告も出ないため、移行後にキャッシュ寿命が既定(5 分)へ戻っていても気づきにくい
  • isLoading の意味が v4 と違う — v4 の isLoading は v5 の isPending。v5 の isLoading は「初回取得中」に狭まった。ローディング表示の条件を isPending にするか isLoading にするかで、refetch 時の画面が変わる
  • リトライ回数が Node とブラウザで違う — 上記のとおり既定はブラウザ 3 / サーバー 0。vitest(Node 環境)でエラー系のテストを書くと「ブラウザより早く失敗する」ことに気づく
  • demo は client:only="react" で描画QueryClient をモジュールスコープに 1 つ作る構成のため、SSR ではリクエスト間でキャッシュを共有してしまう。SSR で使う場合は公式 docs の「Server Rendering」どおりリクエストごとに QueryClient を作る

関連書籍

tech-book.net /books/9784873119380

Reactハンズオンラーニング 第2版 : Webアプリケーション開発のベストプラクティス | tech-book.net

Alex Banks/Eve Porcello/宮崎 空 · オライリー・ジャパン

Webフロントエンドの「今」を学びたい人へ! Facebookが開発したJavaScriptライブラリ「

この本が役立つ理由 — hooks・状態管理・データ取得を含む React 開発の実践知を一冊で。TanStack Query が解決している問題(useEffect fetch の限界)の背景が整理できる
詳細を tech-book.net で見る
tech-book.net /books/9784297140618

実践Next.js -- App Routerで進化するWebアプリ開発 | tech-book.net

吉井 健文 · 技術評論社

最新のNext.jsを現場で使うために実践的な知識を詰め込んだ一冊です。フレームワークの基礎はもちろん、パフォーマンスを上げるための知識や関連ライブラリまで、詳細なサン

この本が役立つ理由 — Next.js App Router のサーバーコンポーネント時代に「クライアント側のサーバー状態管理をどこまで持つか」を考える材料。本記事の SSR 注意点の先にある設計判断に
詳細を tech-book.net で見る

関連記事 / 関連 Topic