Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Tanstack Query

ASecurity

当在 React/Next.js 中用 TanStack Query(React Query)做数据拉取、缓存失效、变更与乐观更新、SSR 水合时使用;做查询键设计、自定义 hook 封装、staleTime/gcTime 调优与 App Router 预取产物;不适用于非异步的纯客户端本地状态(用 useState/Zustand)、后端接口实现或其他数据库 ORM;触发词:TanStack Query、React Query、useQuery、useMutation、乐观更新、缓存失效、SSR 水合。

3 stars
0 votes
0 copies
2 views
Added 9/19/2026
ai-agentstypescriptreactnextjsnodecode-reviewapifrontendfullstack

Works with

cursorcliapi

Security Analysis

A100/100

Scanned 9/19/2026

$npx -y skills add findscripter/everything-skills --skill tanstack-query --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tanstack Query?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Tanstack Query
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/findscripter-tanstack-query/badge)](https://www.skillsdirectory.com/skills/findscripter-tanstack-query)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: tanstack-query
title: TanStack Query 异步状态管理
description: 当在 React/Next.js 中用 TanStack Query(React Query)做数据拉取、缓存失效、变更与乐观更新、SSR 水合时使用;做查询键设计、自定义 hook 封装、staleTime/gcTime 调优与 App Router 预取产物;不适用于非异步的纯客户端本地状态(用 useState/Zustand)、后端接口实现或其他数据库 ORM;触发词:TanStack Query、React Query、useQuery、useMutation、乐观更新、缓存失效、SSR 水合。
domain: 研发/frontend
triggers: [TanStack Query, React Query, useQuery, useMutation, queryKey, 乐观更新, 缓存失效, invalidateQueries, staleTime, SSR 水合, HydrationBoundary, App Router 数据]
tags: [react, nextjs, tanstack-query, react-query, frontend, data-fetching, state-management]
level: 进阶
status: stable
agents: [claude-code, codex, cursor, gemini-cli]
tools: [@tanstack/react-query, react, nextjs, typescript]
requires: []
related: [react-state-management, trpc-typesafe-api, zod-schema-validation, sveltekit-fullstack]
combines_with: [rest-api-endpoint-builder, typescript-advanced-types, shadcn-ui-components]
license: MIT
source: sickn33/agentic-awesome-skills
source_license: MIT
---
## 何时使用

当技术栈已有 TanStack Query(旧名 React Query),需要在 React/Next.js 中处理异步服务端状态时使用:

- 搭建或重构数据拉取逻辑,替换 `useEffect` + `useState` 手写拉取。
- 设计查询键(数组式、强类型、可工厂化)。
- 配置全局或单查询的 `staleTime`/`gcTime`/`retry`/`enabled`。
- 写 `useMutation` 处理 POST/PUT/DELETE,并在成功后 `invalidateQueries` 失效缓存。
- 实现乐观更新(Optimistic Update)即时反馈 + 失败回滚。
- 集成 Next.js App Router:Server Component 预取 + Client 边界水合(hydration)。

铁律:栈里有 TanStack Query,就别再用 `useEffect` 手动拉数据。

不该用的边界:
- 纯客户端本地 UI 状态(表单输入、开关、弹窗)→ 用 `useState`/`useReducer`/Zustand,不是异步状态。
- 后端接口实现、数据库 ORM、GraphQL schema 设计 → 不在本技能范围。
- 全局同步状态(无网络往返)→ 别硬塞进 query 缓存。

## 步骤 / 指令

```
1. 封装 custom hook:把每个 useQuery/useMutation 包成 useUser()/useCreatePost(),
   集中管理 fetcher、TS 类型、queryKey。视图层只写 const { data } = useUser(id)。
2. 设计 queryKey:必须是数组,顺序敏感;筛选/排序参数作为对象进键
   (['issues', { status, sort }])。大型应用用 key 工厂避免拼写漂移。
3. 配 staleTime:默认 0(每次挂载都后台 refetch)。数据非秒级变化就设全局
   staleTime(如 60s)。注意 gcTime 必须 ≥ staleTime。
4. 变更 + 失效:useMutation 的 mutationFn 发写请求,onSuccess 里
   queryClient.invalidateQueries({ queryKey: [...] }) 触发后台重拉。
5. 乐观更新(需即时反馈时):onMutate 取消在途请求→快照旧值→setQueryData 抢先改;
   onError 用 context 回滚;onSettled 再 invalidateQueries 与服务端对齐。
6. Next.js App Router:providers.tsx 用 useState 惰性建 QueryClient;
   Server Component 里 prefetchQuery 后 dehydrate 包进 HydrationBoundary,
   Client Component 用相同 queryKey 的 useQuery 直接读水合缓存,挂载不再发请求。
```

规则:
- 所有 `useQuery`/`useMutation` 一律抽进 custom hook,视图只消费 hook。
- 用 key 工厂统一管理键,杜绝 `['users']` vs `['user']` 拼错。
- 优先 `invalidateQueries` 让其自然重拉,少用 `setQueryData` 手动改缓存(乐观更新除外)。
- 不要把 query 数据同步进本地 React state(`useEffect(() => setLocal(data), [data])`);需要派生态就在 render 时直接派生。

## 示例

custom hook + 强类型 + 依赖查询:
```typescript
import { useQuery } from '@tanstack/react-query';

type User = { id: string; name: string; status: 'active' | 'inactive' };

const fetchUser = async (userId: string): Promise<User> => {
  const res = await fetch(`/api/users/${userId}`);
  if (!res.ok) throw new Error('Failed to fetch user');
  return res.json();
};

export const useUser = (userId: string) =>
  useQuery({
    queryKey: ['users', userId],     // 数组式查询键
    queryFn: () => fetchUser(userId),
    staleTime: 1000 * 60 * 5,        // 5 分钟内视为新鲜,不后台重拉
    enabled: !!userId,               // 依赖查询:userId 存在才执行
  });
```

查询键工厂(大型应用推荐):
```typescript
export const issueKeys = {
  all: ['issues'] as const,
  lists: () => [...issueKeys.all, 'list'] as const,
  list: (filters: string) => [...issueKeys.lists(), { filters }] as const,
  details: () => [...issueKeys.all, 'detail'] as const,
  detail: (id: number) => [...issueKeys.details(), id] as const,
};
```

变更 + 缓存失效:
```typescript
import { useMutation, useQueryClient } from '@tanstack/react-query';

export const useCreatePost = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: async (newPost: { title: string }) => {
      const res = await fetch('/api/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newPost),
      });
      return res.json();
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['posts'] }); // 触发后台重拉
    },
  });
};
```

乐观更新(onMutate 抢先改 → onError 回滚 → onSettled 对齐):
```typescript
export const useUpdateTodo = () => {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: updateTodoFn,
    onMutate: async (newTodo) => {
      await queryClient.cancelQueries({ queryKey: ['todos'] }); // 取消在途请求
      const previousTodos = queryClient.getQueryData(['todos']); // 快照旧值
      queryClient.setQueryData(['todos'], (old: any) =>
        old.map((t: any) => (t.id === newTodo.id ? { ...t, ...newTodo } : t))
      );
      return { previousTodos };                                 // 作为 context 返回
    },
    onError: (err, newTodo, context) => {
      queryClient.setQueryData(['todos'], context?.previousTodos); // 回滚
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] });   // 成败都对齐服务端
    },
  });
};
```

Next.js App Router 预取 + 水合:
```typescript
// app/providers.tsx
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState } from 'react'

export default function Providers({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(
    () => new QueryClient({
      defaultOptions: {
        queries: { staleTime: 60 * 1000, refetchOnWindowFocus: false },
      },
    })
  )
  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}
```
```typescript
// app/posts/page.tsx (Server Component)
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query';
import PostsList from './PostsList';

export default async function PostsPage() {
  const queryClient = new QueryClient();
  await queryClient.prefetchQuery({ queryKey: ['posts'], queryFn: fetchPostsServerSide });
  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <PostsList />  {/* Client 组件用相同 queryKey 读缓存,挂载不再发请求 */}
    </HydrationBoundary>
  );
}
```

## 注意事项

- 无限拉取循环:多因 `queryFn` 在返回前抛未捕获异常(默认 retry 3 次),或被包进不稳定的 `useEffect`。调试时设 `retry: false` 定位。
- `staleTime` vs `gcTime`(旧名 `cacheTime`):`staleTime` 决定何时后台重拉;`gcTime` 决定组件卸载后非活动数据在内存留存多久。`gcTime < staleTime` 会让数据在变陈旧前就被回收,务必 `gcTime ≥ staleTime`。
- 默认 `staleTime: 0` 意味着每次组件重挂载都触发后台 refetch;数据非秒级变化时设全局 `staleTime` 省请求。
- App Router 中 Server 与 Client 必须用同一 `queryKey`,否则水合失配仍会发网络请求。
- `refetchOnWindowFocus: false` 可避免切 Tab 时的激进重拉,按业务取舍。
- 本技能只覆盖前端异步状态层;接口契约、鉴权、错误码语义需结合具体后端验证,勿当作环境无关结论。输入/权限/成功判据缺失时应停下追问。

## 互见

- requires:无。
- related:`code-reviewer`(审查 React 数据层改动的正确性与坏味道)。
- combines_with:无。

---
采编自 sickn33/antigravity-awesome-skills(MIT)。

Attribution

findscripterfindscripter
View sourceSee grades on GitHubMore from findscripter →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Caveman

Terse caveman voice: answer first, fluff gone, every technical fact kept. Use for /caveman, "caveman mode", "talk like caveman", "be brief", "less tokens". Stays on until "stop caveman" or "normal mode".

1100021 votes

Hyperplan

Adversarial multi-agent planning skill. Self-orchestrates 5 hostile category members (unspecified-low, unspecified-high, deep, ultrabrain, artistry) via team-mode for ruthless cross-critique debate, distills only the defensible insights, then MANDATORILY hands the distilled insight bundle to the `plan` agent for executable plan formalization. Use when planning needs maximum rigor and surfacing of weak assumptions, blind spots, and over-engineering. Triggers: 'hyperplan', 'hpp', '/hyperplan', ...

698461 votes

Writing Skills

Create and manage Claude Code skills in HASH repository following Anthropic best practices. Use when creating new skills, modifying skill-rules.json, understanding trigger patterns, working with hooks, debugging skill activation, or implementing progressive disclosure. Covers skill structure, YAML frontmatter, trigger types (keywords, intent patterns), UserPromptSubmit hook, and the 500-line rule. Includes validation and debugging with SKILL_DEBUG. Examples include rust-error-stack, cargo-dep...

3931 votes

Mcp Code Execution

Routes multi-tool workflows through MCP servers for large datasets and pipelines. Use when Bash tool overhead is limiting throughput on data-heavy tasks.

3421 votes

catchup

Recovers the conversation and failed tool calls of a previous Codex, Amp, Claude Code, Antigravity, Cline, Copilot CLI, Cursor, DeepSeek Harness, Grok Build, Kimi, OpenCode, Pi Agent, or ZCode session. Use when the user says "catch up", "what did the last session do", "get me up to speed", "I switched agents", asks to recover/summarize a previous session before continuing, or asks to diagnose or report a catchup failure. Do NOT use for the current conversation, git history, or any non-agent log.

741 votes
View all in ai-agents →