安装与快速开始
TanStack Query(原名 React Query)是 TanStack 生态中的异步状态管理器。它不是一个数据获取库——你提供任何返回 Promise 的函数,它负责缓存、去重、后台更新和过期数据管理。
官方文档:TanStack Query 当前稳定版本:v5.x(2023 年 10 月发布),要求 React 18+ 和 TypeScript 4.7+
前置条件
- React:18.0 或更高版本(使用
useSyncExternalStore) - TypeScript:4.7 或更高版本(推荐)
- Node.js:18.0+
安装
npm install @tanstack/react-query
# 或
yarn add @tanstack/react-query
# 或
pnpm add @tanstack/react-query⚠️ 旧包名
react-query已废弃,v5 统一使用@tanstack/react-query。
React Query Devtools(推荐)
npm install @tanstack/react-query-devtoolsDevtools 帮助你可视化查询状态、缓存数据和手动触发重新获取。仅在开发环境渲染:
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* 你的应用 */}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}项目结构建议
src/
├── query/
│ ├── queryClient.ts # QueryClient 实例 + 全局默认配置
│ ├── options/ # queryOptions / infiniteQueryOptions 工厂
│ │ ├── userOptions.ts
│ │ └── todoOptions.ts
│ └── hooks/ # 自定义 query hooks(封装业务逻辑)
│ ├── useUser.ts
│ └── useTodos.ts
├── components/
├── pages/
└── ...💡 最佳实践:将 QueryClient 和 queryOptions 从组件中分离出来。组件只通过自定义 Hook 消费数据,保持 UI 层干净。
最小化配置
第一步:创建 QueryClient + Provider
// src/query/queryClient.ts
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 5 * 60 * 1000, // 5 分钟内数据视为新鲜
gcTime: 10 * 60 * 1000, // 10 分钟后垃圾回收
retry: 3, // 失败重试 3 次
refetchOnWindowFocus: true, // 窗口重新聚焦时重新获取
},
mutations: {
retry: 1, // mutation 默认不重试
},
},
})// src/main.tsx
import { QueryClientProvider } from '@tanstack/react-query'
import { queryClient } from './query/queryClient'
import App from './App'
function Root() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
)
}
export default Root第二步:第一个查询(useQuery)
import { useQuery } from '@tanstack/react-query'
interface Todo {
id: number
title: string
completed: boolean
}
async function fetchTodos(): Promise<Todo[]> {
const res = await fetch('https://jsonplaceholder.typicode.com/todos?_limit=5')
if (!res.ok) throw new Error('获取失败')
return res.json()
}
function TodoList() {
const { data, isPending, error, isFetching } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})
if (isPending) return <div>加载中...</div>
if (error) return <div>出错了:{error.message}</div>
return (
<div>
<h2>待办列表 {isFetching && <small>🔄 后台更新中...</small>}</h2>
<ul>
{data.map(todo => (
<li key={todo.id}>
{todo.completed ? '✅' : '⬜'} {todo.title}
</li>
))}
</ul>
</div>
)
}⚠️ v5 只接受对象语法:
useQuery({ queryKey, queryFn })。v4 的useQuery(key, fn, opts)位置参数已移除。
第三步:第一个变更(useMutation)
import { useMutation, useQueryClient } from '@tanstack/react-query'
function AddTodo() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: (title: string) =>
fetch('https://jsonplaceholder.typicode.com/todos', {
method: 'POST',
body: JSON.stringify({ title, completed: false, userId: 1 }),
headers: { 'Content-Type': 'application/json' },
}).then(res => res.json()),
onSuccess: () => {
// 变更成功后使缓存失效,触发重新获取
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})
return (
<form
onSubmit={(e) => {
e.preventDefault()
const input = (e.target as HTMLFormElement).elements.namedItem('title') as HTMLInputElement
if (input.value.trim()) {
mutation.mutate(input.value.trim())
input.value = ''
}
}}
>
<input name="title" placeholder="添加待办..." />
<button type="submit" disabled={mutation.isPending}>
{mutation.isPending ? '添加中...' : '添加'}
</button>
{mutation.isError && <p>添加失败:{mutation.error.message}</p>}
</form>
)
}v5 关键变化速查(v4 → v5)
| v4(废弃) | v5(替换) | 说明 |
|---|---|---|
useQuery(key, fn, opts) |
useQuery({ queryKey, queryFn, ... }) |
仅对象语法 |
cacheTime |
gcTime |
垃圾回收时间,更准确 |
isLoading |
isPending |
首次加载无数据 |
isLoading(新含义) |
isPending && isFetching |
同时 pending 和 fetching |
status: 'loading' |
status: 'pending' |
语义更准确 |
keepPreviousData: true |
placeholderData: keepPreviousData |
导入辅助函数 |
onSuccess / onError(useQuery) |
已移除 | 用 useEffect 或 mutation 回调 |
useErrorBoundary |
throwOnError |
框架无关命名 |
hashQueryKey |
hashKey |
也支持 mutation key |
快速启动检查清单
- 安装
@tanstack/react-query - 创建
QueryClient实例(配置staleTime和gcTime) - 用
QueryClientProvider包裹应用 - (可选)添加
ReactQueryDevtools - 编写第一个
useQueryhook 调用 - 确认
isPending/error/data三个分支都有处理