ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-06-13上級

TanStack Query v5 のキャッシュ整合性を壊さない設計 — 無効化境界・楽観的更新・SSR の落とし穴を Antigravity で詰めていく

いいねを押すと表示が一瞬で巻き戻る、別タブから戻ると古い値が残る。TanStack Query v5 で起きるキャッシュ不整合を「壊れる3地点」から逆算し、無効化境界・onMutateのロールバック・QueryClientのリクエスト分離を実コードで設計します。

antigravity345TanStack QueryReact QueryNext.js6TypeScript9キャッシュ設計状態管理2

プレミアム記事

「いいね」を押した直後にハートが赤くなり、コンマ数秒後に元の灰色へ戻る。サーバーは 200 を返しているのに、画面だけが嘘をついている。個人開発のアプリでこの挙動を初めて見たとき、私はミューテーションの実装を何度も読み返しました。コードは教科書どおりに見えるのに、表示だけが時々巻き戻る。原因は onError でも mutationFn でもなく、ミューテーションの直前に走っていた別のフェッチでした。

TanStack Query v5(旧 React Query)の不具合の多くは、こういう「個別のバグに見えて、実はキャッシュ整合性の設計問題」という形をとります。ライブラリ自体はよくできていて、単体の API は素直です。けれども、複数のクエリとミューテーションが同じキャッシュを共有し始めた瞬間に、整合性をどう保つかという判断が一気に必要になります。Antigravity の AI エージェントはフックの雛形を数秒で書いてくれますが、この「整合性をどこで担保するか」だけは、生成されたコードを読む側が握っていないと崩れます。

ここでは、私が個人開発の中で実際に踏んだ不整合を、起きる場所ごとに分類して潰していきます。コードの断片を並べるより、「なぜそこで壊れるのか」を先に共有したほうが、明日の自分のコードに効くはずです。

キャッシュが壊れるのは、だいたい3つの地点だけ

数年運用してみて気づいたのは、TanStack Query の不整合はほぼ3つの地点に集約されるということです。第一に、ミューテーション後の無効化境界が広すぎる/狭すぎる地点。第二に、楽観的更新のロールバック経路が欠けている地点。第三に、SSR で QueryClient を共有してしまい、別リクエストのデータが混ざる地点。

逆に言えば、新しいバグに遭遇しても「これは3つのうちどれだ」と問えば、調査範囲がぐっと狭まります。冒頭のハートが巻き戻る例は、二番目に見えて実は「無効化と楽観更新の競合」、つまり一番目と二番目の境界線上の問題でした。順番に見ていきます。

まず v5 の前提 — isPendingsignal を雛形に焼き込む

整合性の話に入る前に、v5 で土台になる2点だけ押さえます。v4 までと違い、status: 'loading'pending に改名され、isPending(キャッシュが空でまだ取得中)と isFetching(再取得中だが古いデータは見せられる)が明確に分かれました。この区別を曖昧にすると、再取得のたびにスケルトンが出るちらつきUIになります。

import { useQuery } from "@tanstack/react-query";
 
export function useUserProfile(userId: string) {
  return useQuery({
    queryKey: ["users", userId, "profile"],
    // signal を必ず受けて fetch に渡す — アンマウント時の中断に直結する
    queryFn: ({ signal }) => fetchUserProfile(userId, { signal }),
    staleTime: 60_000,
    gcTime: 5 * 60_000,
    enabled: Boolean(userId),
  });
}
 
async function fetchUserProfile(userId: string, { signal }: { signal: AbortSignal }) {
  const res = await fetch(`/api/users/${userId}`, { signal });
  if (!res.ok) throw new Error(`Failed to fetch user: ${res.status}`);
  return (await res.json()) as UserProfile;
}

signalqueryFn の引数で受けて fetch に渡す。これは v4 でも可能でしたが、v5 では「省略する理由がない」標準作法になりました。Antigravity に「ユーザー取得フックを書いて」と頼むと signal を落とした雛形が返ることがあります。私は生成コードをマージする前のチェック項目に必ずこれを入れています。アンマウント時にリクエストを止められるかどうかは、画面遷移の多いアプリほどサーバー負荷に効いてきます。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
キャッシュ不整合が生まれる3地点(無効化境界・楽観更新のロールバック・SSRのClient共有)を切り分ける診断軸
cancelQueries→snapshot→setQueryData→onSettledの5手をテンプレ化し、巻き戻りバグを構造的に消す実装
リクエストごとにQueryClientを作る理由と、シングルトン化が個人情報リークになる仕組み
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

アプリ開発2026-03-25
Antigravity + tRPC で型安全なフルスタックAPI開発 — エンドツーエンドの型推論で開発効率を劇的に向上させる
Antigravity の AI エージェントと tRPC を組み合わせて、サーバーからクライアントまで完全に型安全な API を構築する方法を解説します。Zod バリデーション、React Query 統合、エラーハンドリングまで実践的に学べます。
アプリ開発2026-04-15
Antigravity × Firebase Data Connect:GraphQL型安全APIをAIで最速構築する実践アーキテクチャ
Firebase Data Connectの完全な実装ガイド。GraphQLスキーマ定義からFirebase Auth統合、Antigravity AIによるクエリ自動生成、本番デプロイまで動作確認済みコードで解説します。
アプリ開発2026-06-12
Android 17 で縦固定が無視される前に — 壁紙アプリ4本の大画面対応を Antigravity と棚卸しした記録
Android 17 は大画面でアプリの向き・リサイズ制限を無視するようになります。縦固定で育ててきた壁紙アプリ4本のマニフェストとコードを Antigravity エージェントと棚卸しし、プレビュー設計を見直すまでの手順と判断を記録しました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →