关于 tanstack-query
面向使用异步服务端状态的应用开发者的 TanStack Query 技能。介绍查询、变更、缓存及迁移模式,并说明常见实现问题。
主要功能
- 01查询与变更模式
- 02缓存失效与更新
- 03无限查询与分页
- 04离线与持久化指南
- 05v5 迁移参考
适用场景
- 01构建无限滚动数据视图
- 02在变更后协调缓存更新
- 03处理应用离线数据
- 04将项目从 v4 迁移至 v5
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ oakoss/ agent-skills --skill tanstack-query安装后在 Claude Code 中输入/tanstack-query确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/basic-patterns.mdcaching-coordination.mdcaching.mddata-transformations.mderror-handling.mdinfinite-queries.mdknown-issues.mdmutations.mdoffline-mode.mdperformance.mdquery-keys.mdssr-hydration.mdtesting.mdtypescript-patterns.mdwebsocket-integration.md详细介绍
TanStack Query
概述
TanStack Query 是一个异步状态管理器,而不是数据获取库。你需要提供一个返回 Promise 的 queryFn;React Query 会处理缓存、去重、后台更新和过期数据管理。
适用场景: 无限滚动、离线优先应用、聚焦或重新连接时自动重新获取数据、复杂的缓存失效、React Native、混合服务端/客户端应用。
不适用场景: 纯同步状态(使用 useState/Zustand)、规范化的 GraphQL 缓存(Apollo/urql)、仅使用服务端组件的应用(原生 fetch)、简单的获取并显示(服务端组件)。
快速参考
| 模式 | API | 要点 |
|---|---|---|
| 基本查询 | useQuery({ queryKey, queryFn }) | 将参数包含在 queryKey 中 |
| Suspense 查询 | useSuspenseQuery(options) | 不允许使用 enabled 选项 |
| 并行查询 | useQueries({ queries, combine }) | 动态并行获取数据 |
| 依赖查询 | useQuery({ enabled: !!dep }) | 等待前置数据 |
| 查询选项 | queryOptions({ queryKey, queryFn }) | 可复用、类型安全的配置 |
| 基本变更 | useMutation({ mutationFn, onSuccess }) | 成功时使缓存失效 |
| 变更状态 | useMutationState({ filters, select }) | 跨组件跟踪变更 |
| 乐观更新 | onMutate -> cancel -> snapshot -> set | 在 onError 中回滚 |
| 无限查询 | useInfiniteQuery({ initialPageParam }) | v5 中必须设置 initialPageParam |
| 预取 | queryClient.prefetchQuery(options) | 在悬停或有意图时预加载 |
| 失效 | queryClient.invalidateQueries({ queryKey }) | 默认模糊匹配,且仅匹配活动查询 |
| 取消 | queryFn: ({ signal }) => fetch(url, { signal }) | key 变更时自动取消 |
| 选择转换 | select: (data) => data.filter(...) | 保留结构共享 |
| 跳过令牌 | queryFn: id ? () => fetch(id) : skipToken | 类型安全地按条件禁用 |
| 串行变更 | useMutation({ scope: { id } }) | 相同 scope ID 的变更按顺序运行 |
v5 迁移快速参考
| v4(已移除) | v5(替代用法) |
|---|---|
useQuery(key, fn, opts) | useQuery({ queryKey, queryFn, ...opts }) |
cacheTime | gcTime |
isLoading(无数据时) | isPending |
keepPreviousData: true | placeholderData: keepPreviousData |
查询中的 onSuccess/onError | useEffect 或变更回调 |
useErrorBoundary | throwOnError |
无 initialPageParam | 必须设置 initialPageParam |
错误类型为 unknown | 错误类型默认为 Error |
常见错误
| 错误 | 正确做法 |
|---|---|
在检查 data 之前检查 isPending | 优先检查数据:依次检查 data -> error -> isPending |
将服务端状态复制到本地 useState | 直接使用数据或采用派生状态模式 |
| 在组件中创建 QueryClient | 在组件外创建一次,或在 useState 中创建 |
参数变化时使用 refetch() | 将参数包含在 queryKey 中,让它自动重新获取 |
useQuery 和 useInfiniteQuery 使用相同的 key | 使用不同的 key 片段(缓存结构不同) |
内联使用 select,但未进行记忆化 | 提取为稳定函数或使用 useCallback |
使用 catch 却不重新抛出 | 在 queryFn 中抛出错误(fetch 遇到 4xx/5xx 时不会拒绝) |
在 useQuery 上手动指定泛型 | 为 queryFn 的返回值指定类型,让类型推断生效 |
| 解构 query 以缩窄类型 | 保留完整的 query 对象,以正确缩窄类型 |
在 useSuspenseQuery 中使用 enabled | 使用条件渲染来挂载/卸载组件 |
| SSR 时未等待预取完成 | 等待 prefetchQuery,避免水合不匹配 |
invalidateQueries 未重新获取所有查询 | 对非活跃查询使用 refetchType: 'all' |
委派
- 查询模式探索:使用
ExploreAgent - 缓存策略审查:使用
TaskAgent - 代码审查:委派给
code-reviewerAgent
如果有
tanstack-routerskill,请将路由加载器和预加载模式委派给它。 如果有tanstack-formskill,请将表单提交和 mutation 协调委派给它。 如果有tanstack-tableskill,请将服务端表格模式委派给它。 如果有tanstack-startskill,请将服务端函数和 SSR 数据加载委派给它。 如果有tanstack-devtoolsskill,请将查询缓存调试和检查委派给它。 如果有tanstack-dbskill,请将响应式客户端数据库和实时查询模式委派给它。 如果有tanstack-virtualskill,请将列表虚拟化和无限滚动渲染委派给它。 如果有tanstack-storeskill,请将共享的客户端响应式状态管理委派给它。 如果有electricsqlskill,请将 ElectricSQL 实时 Postgres 同步模式委派给它。 如果有local-firstskill,请将 local-first 架构决策和同步引擎选择委派给它。