Skip to content
安装与快速开始

安装与快速开始

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-devtools

Devtools 帮助你可视化查询状态、缓存数据和手动触发重新获取。仅在开发环境渲染:

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 实例(配置 staleTimegcTime
  • QueryClientProvider 包裹应用
  • (可选)添加 ReactQueryDevtools
  • 编写第一个 useQuery hook 调用
  • 确认 isPending / error / data 三个分支都有处理