@tanstack/react-query:React 服务器状态管理与数据同步解决方案

1 概述

@tanstack/react-query 是一个功能强大的异步状态管理库,专为简化 React 应用中的服务器状态管理而设计。它提供了一套全面的工具集,用于处理数据获取、缓存、同步和更新服务器状态,使开发者能够专注于业务逻辑而非数据获取细节。

作为现代前端开发的关键工具,@tanstack/react-query 解决了传统数据获取方案中的诸多痛点:

  • 自动缓存与失效管理,减少不必要的网络请求
  • 智能重试与背景刷新机制,提升用户体验
  • 简洁的 API 设计,降低异步数据处理的复杂性
  • 深度整合 TypeScript,提供完善的类型安全保障
  • 与 React 生态无缝集成,支持 Suspense 等现代特性

最新版本 v5.84.2 带来了多项重要改进,包括统一的参数对象化 API、增强的类型推断能力、优化的缓存策略以及对 React 18 特性的更好支持。这些更新进一步提升了库的易用性和性能,使其成为构建高性能 React 应用的理想选择。

无论是小型项目还是大型企业级应用,@tanstack/react-query 都能显著简化数据管理流程,减少样板代码,并提供一致且可预测的状态管理体验。

2 安装与配置

2.1 环境要求

@tanstack/react-query v5 需要以下环境支持:

  • React: 18.0.0 或更高版本
  • TypeScript: 4.7 或更高版本(可选)
  • Node.js: 16.0.0 或更高版本

2.2 安装命令

使用 npm

bash 复制代码
# 安装核心库
npm install @tanstack/react-query

# 安装开发工具(可选,用于调试)
npm install --save-dev @tanstack/react-query-devtools

# 如果使用 TypeScript,确保安装类型定义
npm install --save-dev @types/react @types/react-dom

使用 yarn

bash 复制代码
# 安装核心库
yarn add @tanstack/react-query

# 安装开发工具
yarn add -D @tanstack/react-query-devtools

使用 pnpm

bash 复制代码
# 安装核心库
pnpm add @tanstack/react-query

# 安装开发工具
pnpm add -D @tanstack/react-query-devtools

安装指定版本

如需安装特定版本(如本文介绍的 v5.84.2):

bash 复制代码
npm install @tanstack/react-query@5.84.2
npm install --save-dev @tanstack/react-query-devtools@5.84.2

2.3 项目初始化

创建新项目(可选)

如果您正在创建新的 React 项目,推荐使用以下方式:

bash 复制代码
# 使用 Create React App
npx create-react-app my-app --template typescript
cd my-app

# 或使用 Vite(推荐,更快的开发体验)
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install

# 安装 React Query
npm install @tanstack/react-query @tanstack/react-query-devtools

2.4 基本配置

步骤 1:创建 QueryClient

src/lib/queryClient.ts 文件中创建 QueryClient 实例:

tsx 复制代码
// src/lib/queryClient.ts
import { QueryClient } from '@tanstack/react-query'

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 60 * 1000, // 数据保鲜时间:1分钟
      gcTime: 10 * 60 * 1000, // 垃圾回收时间:10分钟
      retry: 1, // 失败重试次数
      refetchOnWindowFocus: true, // 窗口聚焦时重新获取
      refetchOnReconnect: true, // 网络重连时重新获取
    },
    mutations: {
      retry: 1, // 变更操作重试次数
    },
  },
})

步骤 2:配置应用入口

src/main.tsx(Vite)或 src/index.tsx(CRA)中配置 Provider:

tsx 复制代码
// src/main.tsx (Vite) 或 src/index.tsx (CRA)
import React from 'react'
import ReactDOM from 'react-dom/client'
import { QueryClientProvider } from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { queryClient } from './lib/queryClient'
import App from './App'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      {/* 仅在开发环境显示开发工具 */}
      {process.env.NODE_ENV === 'development' && (
        <ReactQueryDevtools initialIsOpen={false} />
      )}
    </QueryClientProvider>
  </React.StrictMode>
)

步骤 3:配置详细选项

如需更精细的控制,可以扩展 QueryClient 配置:

tsx 复制代码
// src/lib/queryClient.ts
import { QueryClient } from '@tanstack/react-query'

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 数据缓存配置
      staleTime: 5 * 60 * 1000, // 5分钟内数据被认为是新鲜的
      gcTime: 30 * 60 * 1000, // 30分钟后清理未使用的数据
      
      // 重试配置
      retry: (failureCount, error) => {
        // 对于 404 错误不重试
        if (error.status === 404) return false
        // 最多重试 3 次
        return failureCount < 3
      },
      retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000),
      
      // 自动重新获取配置
      refetchOnWindowFocus: true,
      refetchOnReconnect: true,
      refetchOnMount: true,
      
      // 网络模式
      networkMode: 'online', // 'online' | 'always' | 'offlineFirst'
    },
    mutations: {
      retry: 1,
      networkMode: 'online',
    },
  },
})

2.5 第一个查询示例

创建 API 函数

首先创建一个 API 服务文件 src/services/api.ts

tsx 复制代码
// src/services/api.ts
export interface User {
  id: number
  name: string
  email: string
  username: string
}

export interface Post {
  id: number
  title: string
  body: string
  userId: number
}

// 模拟 API 调用
const API_BASE = 'https://jsonplaceholder.typicode.com'

export const fetchUsers = async (): Promise<User[]> => {
  const response = await fetch(`${API_BASE}/users`)
  if (!response.ok) {
    throw new Error('获取用户列表失败')
  }
  return response.json()
}

export const fetchUser = async (userId: number): Promise<User> => {
  const response = await fetch(`${API_BASE}/users/${userId}`)
  if (!response.ok) {
    throw new Error(`获取用户 ${userId} 失败`)
  }
  return response.json()
}

export const fetchPosts = async (): Promise<Post[]> => {
  const response = await fetch(`${API_BASE}/posts`)
  if (!response.ok) {
    throw new Error('获取文章列表失败')
  }
  return response.json()
}

创建第一个组件

创建 src/components/UserList.tsx 组件:

tsx 复制代码
// src/components/UserList.tsx
import { useQuery } from '@tanstack/react-query'
import { fetchUsers, User } from '../services/api'

export function UserList() {
  const {
    data: users,
    isPending,
    isError,
    error
  } = useQuery({
    queryKey: ['users'],
    queryFn: fetchUsers,
    staleTime: 5 * 60 * 1000, // 5分钟内数据保持新鲜
  })

  if (isPending) {
    return <div className="loading">正在加载用户列表...</div>
  }

  if (isError) {
    return (
      <div className="error">
        <h3>加载失败</h3>
        <p>{error.message}</p>
        <button onClick={() => window.location.reload()}>
          重试
        </button>
      </div>
    )
  }

  return (
    <div className="user-list">
      <h2>用户列表</h2>
      <div className="users">
        {users?.map((user: User) => (
          <div key={user.id} className="user-card">
            <h3>{user.name}</h3>
            <p>用户名: {user.username}</p>
            <p>邮箱: {user.email}</p>
          </div>
        ))}
      </div>
    </div>
  )
}

在 App 组件中使用

更新 src/App.tsx

tsx 复制代码
// src/App.tsx
import { UserList } from './components/UserList'
import './App.css'

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <h1>React Query 示例应用</h1>
      </header>
      <main>
        <UserList />
      </main>
    </div>
  )
}

export default App

添加基本样式

src/App.css 中添加样式:

css 复制代码
/* src/App.css */
.App {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

.App-header {
  text-align: center;
  margin-bottom: 30px;
}

.loading, .error {
  text-align: center;
  padding: 20px;
  margin: 20px 0;
}

.error {
  background-color: #fee;
  border: 1px solid #fcc;
  border-radius: 4px;
  color: #c33;
}

.error button {
  background-color: #c33;
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 10px;
}

.user-list h2 {
  margin-bottom: 20px;
}

.users {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.user-card {
  background: #f9f9f9;
  padding: 20px;
  border-radius: 8px;
  border: 1px solid #e0e0e0;
}

.user-card h3 {
  margin: 0 0 10px 0;
  color: #333;
}

.user-card p {
  margin: 5px 0;
  color: #666;
}

运行应用

现在您可以启动应用查看效果:

bash 复制代码
npm run dev  # 如果使用 Vite
# 或
npm start    # 如果使用 Create React App

打开浏览器访问 http://localhost:5173(Vite)或 http://localhost:3000(CRA),您将看到:

  1. 加载状态: 初始显示"正在加载用户列表..."
  2. 数据展示: 加载完成后显示用户卡片列表
  3. 错误处理: 如果网络失败,显示错误信息和重试按钮
  4. 开发工具: 按 F12 可以看到 React Query DevTools(如果已安装)

关键概念说明

这个示例展示了 React Query 的核心概念:

  1. queryKey : ['users'] - 唯一标识这个查询
  2. queryFn : fetchUsers - 实际的数据获取函数
  3. 自动缓存: 相同的查询键会复用缓存数据
  4. 加载状态 : isPending 表示首次加载
  5. 错误处理 : isErrorerror 提供错误信息
  6. 类型安全 : TypeScript 自动推断 users 的类型为 User[] | undefined

3 核心API变更

3.1 参数对象化

v5 版本统一采用对象参数格式,替代了之前的多重载形式:

tsx 复制代码
// 旧版用法
useQuery('todos', fetchTodos, { staleTime: 5000 })

// v5 新用法
useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 5000
})

这一变更提高了类型安全性和代码一致性,所有核心钩子(useQuery、useInfiniteQuery、useMutation 等)均采用相同模式。

3.2 状态命名调整

状态命名更加精确,明确区分不同加载阶段:

tsx 复制代码
// 旧版
{ isLoading, isSuccess, isError }

// v5 新版
{ isPending, isLoading, isSuccess, isError }
  • isPending: 查询已开始但尚未有数据
  • isLoading: 首次加载数据(初始加载)
  • isFetching: 数据刷新中(背景刷新)

3 TypeScript 支持

3.1 类型推断优化

v5 大幅改进了类型推断能力,大多数情况下无需显式指定泛型:

tsx 复制代码
// 自动推断 data 类型为 Group[] | undefined
const fetchGroups = () : Promise<Group[]> => 
  axios.get('/groups').then((response) => response.data)

const { data } = useQuery({ 
  queryKey: ['groups'], 
  queryFn: fetchGroups 
})

3.2 类型窄化

通过状态判断自动窄化数据类型:

tsx 复制代码
const { data, isSuccess } = useQuery({ 
  queryKey: ['user'], 
  queryFn: fetchUser 
})

if (isSuccess) {
  // TypeScript 知道此时 data 一定存在
  console.log(data.name) // 正确推断类型
}

3.3 全局错误类型配置

可通过模块增强定义全局错误类型:

tsx 复制代码
import '@tanstack/react-query'
import type { AxiosError } from 'axios'

declare module '@tanstack/react-query' {
  interface Register {
    defaultError: AxiosError
  }
}

// 错误类型自动推断为 AxiosError | null
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })

4 核心功能示例

4.1 基础查询

tsx 复制代码
const { 
  data, 
  isPending, 
  isError, 
  error 
} = useQuery({
  queryKey: ['todos', todoId], // 数组形式的查询键
  queryFn: () => fetchTodo(todoId),
  staleTime: 60 * 1000, // 数据保鲜时间 1 分钟
  retry: 2 // 失败重试次数
})

if (isPending) return <div>加载中...</div>
if (isError) return <div>错误: {error.message}</div>

return <div>{data.title}</div>

4.2 数据转换

使用 select 选项转换查询结果:

tsx 复制代码
const { data } = useQuery({
  queryKey: ['user'],
  queryFn: fetchUser,
  select: (user) => ({
    id: user.id,
    fullName: `${user.firstName} ${user.lastName}`
  })
})

// data 类型自动推断为 { id: number; fullName: string }

4.3 变更操作

使用 useMutation 处理数据更新:

tsx 复制代码
const queryClient = useQueryClient()

const mutation = useMutation({
  mutationFn: updateTodo,
  onSuccess: () => {
    // 更新成功后使相关查询失效,触发重新获取
    queryClient.invalidateQueries({ queryKey: ['todos'] })
  }
})

mutation.mutate({ id: 1, title: '更新后的标题' })

if (mutation.isPending) return <button disabled>保存中...</button>

return (
  <button onClick={() => mutation.mutate({ id: 1, title: '新标题' })}>
    更新
  </button>
)

4.4 查询选项复用

使用 queryOptions helper 复用查询配置:

tsx 复制代码
import { queryOptions } from '@tanstack/react-query'

function todoOptions(todoId: number) {
  return queryOptions({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodo(todoId),
    staleTime: 5 * 1000
  })
}

// 在组件中使用
const { data } = useQuery(todoOptions(1))

// 在预获取中使用
queryClient.prefetchQuery(todoOptions(2))

4 高级查询功能

4.1 无限查询

使用 useInfiniteQuery 实现无限滚动或加载更多:

tsx 复制代码
import { useInfiniteQuery } from '@tanstack/react-query'

function fetchProjects({ pageParam = 0 }) {
  return fetch(`/api/projects?page=${pageParam}`).then(res => res.json())
}

function Projects() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: ['projects'],
    queryFn: fetchProjects,
    getNextPageParam: (lastPage) => lastPage.nextCursor,
    initialPageParam: 0,
  })

  return (
    <div>
      {data?.pages.map((page, index) => (
        <div key={index}>
          {page.projects.map(project => (
            <p key={project.id}>{project.name}</p>
          ))}
        </div>
      ))}
      <button
        onClick={() => fetchNextPage()}
        disabled={!hasNextPage || isFetchingNextPage}
      >
        {isFetchingNextPage ? '加载中...' : '加载更多'}
      </button>
    </div>
  )
}

4.2 依赖查询

实现查询之间的依赖关系:

tsx 复制代码
function UserProfile({ userId }) {
  const { data: user } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetchUser(userId),
  })

  // 依赖 user 数据的查询
  const { data: posts } = useQuery({
    queryKey: ['posts', user?.id],
    queryFn: () => fetchPosts(user.id),
    enabled: !!user, // 仅当 user 存在时执行
  })

  return <div>{/* 渲染用户和帖子 */}</div>
}

5 状态更新与缓存

5.1 乐观更新

在服务器确认前更新UI,提升用户体验:

tsx 复制代码
const queryClient = useQueryClient()

const mutation = useMutation({
  mutationFn: updateTodo,
  onMutate: async (newTodo) => {
    // 取消当前查询
    await queryClient.cancelQueries({ queryKey: ['todo', newTodo.id] })
    
    // 保存当前数据
    const previousTodo = queryClient.getQueryData(['todo', newTodo.id])
    
    // 乐观更新
    queryClient.setQueryData(['todo', newTodo.id], newTodo)
    
    // 返回上下文
    return { previousTodo }
  },
  onError: (err, newTodo, context) => {
    // 发生错误时回滚
    queryClient.setQueryData(
      ['todo', newTodo.id],
      context.previousTodo
    )
  },
  onSettled: (newTodo) => {
    // 无论成功失败,重新验证
    queryClient.invalidateQueries({ queryKey: ['todo', newTodo.id] })
  },
})

5.2 查询失效与重新验证

手动控制查询缓存:

tsx 复制代码
// 使单个查询失效
queryClient.invalidateQueries({ queryKey: ['todos', 1] })

// 使所有 todos 相关查询失效
queryClient.invalidateQueries({ queryKey: ['todos'] })

// 强制重新获取,忽略缓存
queryClient.invalidateQueries({ queryKey: ['todos'], force: true })

// 预获取数据
queryClient.prefetchQuery({
  queryKey: ['todos', 2],
  queryFn: () => fetchTodo(2),
})

6 性能优化

6.1 查询结果选择器

使用 select 优化重渲染:

tsx 复制代码
const { data: todoCount } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  select: (todos) => todos.filter(todo => !todo.completed).length,
})

6.2 禁用自动重试

在表单提交等场景禁用自动重试:

tsx 复制代码
useMutation({
  mutationFn: submitForm,
  retry: false, // 禁用重试
})

6.3 结构化查询键

使用数组形式的查询键提高缓存效率:

tsx 复制代码
// 基础查询键
useQuery({ queryKey: ['todos'] })

// 带参数的查询键
useQuery({ queryKey: ['todos', { status: 'active', page: 1 }] })

// 嵌套资源查询键
useQuery({ queryKey: ['user', 1, 'posts'] })

7 最佳实践

7.1 自定义 Hooks 封装

将查询逻辑封装为自定义 Hooks:

tsx 复制代码
// hooks/useTodos.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'

export function useTodos() {
  return useQuery({
    queryKey: ['todos'],
    queryFn: fetchTodos,
  })
}

export function useAddTodo() {
  const queryClient = useQueryClient()
  
  return useMutation({
    mutationFn: addTodo,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['todos'] })
    },
  })
}

7.2 错误处理策略

全局错误处理配置:

tsx 复制代码
// 创建客户端时配置全局错误处理
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      onError: (error) => {
        console.error('查询错误:', error)
        // 可以在这里显示全局错误提示
      },
    },
    mutations: {
      onError: (error) => {
        console.error('变更错误:', error)
      },
    },
  },
})

7.3 与 React Suspense 集成

使用 useSuspenseQuery 简化加载状态处理:

tsx 复制代码
import { useSuspenseQuery } from '@tanstack/react-query'

function TodoDetails({ todoId }) {
  const { data } = useSuspenseQuery({
    queryKey: ['todo', todoId],
    queryFn: () => fetchTodo(todoId),
  })

  return <div>{data.title}</div>
}

// 在父组件中使用 Suspense
function TodoPage({ todoId }) {
  return (
    <React.Suspense fallback={<div>加载中...</div>}>
      <TodoDetails todoId={todoId} />
    </React.Suspense>
  )
}

8 常见问题与故障排除

8.1 安装相关问题

问题:安装后导入失败

bash 复制代码
Error: Cannot find module '@tanstack/react-query'

解决方案:

  1. 确认是否正确安装:
bash 复制代码
npm list @tanstack/react-query
  1. 清理缓存并重新安装:
bash 复制代码
npm cache clean --force
rm -rf node_modules package-lock.json
npm install
  1. 检查 Node.js 版本是否符合要求(>= 16.0.0)

问题:TypeScript 类型错误

bash 复制代码
Cannot find module '@tanstack/react-query' or its corresponding type declarations

解决方案:

确保安装了正确的版本和类型定义:

bash 复制代码
npm install @tanstack/react-query@latest
npm install --save-dev @types/react @types/react-dom

8.2 配置相关问题

问题:Provider 未正确配置

bash 复制代码
Error: useQuery must be used within a QueryClientProvider

解决方案:

确保在应用根部正确包装 QueryClientProvider

tsx 复制代码
// ❌ 错误
function App() {
  return <UserList /> // useQuery 在这里会失败
}

// ✅ 正确  
function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <UserList />
    </QueryClientProvider>
  )
}

问题:开发工具不显示

解决方案:

  1. 确认已安装开发工具:
bash 复制代码
npm install --save-dev @tanstack/react-query-devtools
  1. 正确导入和使用:
tsx 复制代码
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'

// 确保在 QueryClientProvider 内部
<QueryClientProvider client={queryClient}>
  <App />
  <ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>

8.3 查询相关问题

问题:数据不会自动刷新

可能原因:

  • staleTime 设置过长
  • 禁用了自动重新获取

解决方案:

tsx 复制代码
useQuery({
  queryKey: ['data'],
  queryFn: fetchData,
  staleTime: 0, // 立即标记为过期
  refetchOnWindowFocus: true, // 窗口聚焦时刷新
  refetchOnReconnect: true, // 网络重连时刷新
})

问题:查询一直处于 pending 状态

可能原因:

  • queryFn 没有返回 Promise
  • 网络请求被阻塞
  • enabled 选项设置为 false

解决方案:

  1. 检查 queryFn 是否正确:
tsx 复制代码
// ❌ 错误 - 没有返回 Promise
const fetchData = () => {
  fetch('/api/data').then(res => res.json())
}

// ✅ 正确
const fetchData = () => {
  return fetch('/api/data').then(res => res.json())
}

// ✅ 或使用 async/await
const fetchData = async () => {
  const res = await fetch('/api/data')
  return res.json()
}
  1. 检查 enabled 选项:
tsx 复制代码
useQuery({
  queryKey: ['data'],
  queryFn: fetchData,
  enabled: true, // 确保查询已启用
})

问题:错误处理不生效

解决方案:

确保在 queryFn 中正确抛出错误:

tsx 复制代码
const fetchData = async () => {
  const response = await fetch('/api/data')
  
  // ❌ 错误 - 不会触发错误状态
  if (!response.ok) {
    console.error('请求失败')
    return null
  }
  
  // ✅ 正确 - 会触发错误状态
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`)
  }
  
  return response.json()
}

8.4 性能相关问题

问题:组件频繁重渲染

可能原因:

  • 查询键包含不稳定的引用
  • 没有使用 select 优化数据选择

解决方案:

  1. 使用稳定的查询键:
tsx 复制代码
// ❌ 错误 - 每次渲染都会创建新对象
const { data } = useQuery({
  queryKey: ['user', { id: userId, active: true }],
  queryFn: fetchUser
})

// ✅ 正确 - 使用基本类型
const { data } = useQuery({
  queryKey: ['user', userId, 'active'],
  queryFn: fetchUser
})
  1. 使用 select 优化:
tsx 复制代码
const { data } = useQuery({
  queryKey: ['users'],
  queryFn: fetchUsers,
  select: users => users.filter(user => user.active), // 只在数据变化时重新计算
})

问题:内存占用过高

解决方案:

调整缓存配置:

tsx 复制代码
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: 5 * 60 * 1000, // 5分钟后清理未使用的数据
      staleTime: 1 * 60 * 1000, // 1分钟后标记为过期
    },
  },
})

8.5 网络相关问题

问题:离线时查询失败

解决方案:

配置网络模式:

tsx 复制代码
useQuery({
  queryKey: ['data'],
  queryFn: fetchData,
  networkMode: 'offlineFirst', // 离线优先模式
  retry: (failureCount, error) => {
    // 网络错误时不重试
    if (error.name === 'NetworkError') return false
    return failureCount < 3
  }
})

问题:请求超时

解决方案:

queryFn 中添加超时控制:

tsx 复制代码
const fetchWithTimeout = async (url: string, timeout = 10000) => {
  const controller = new AbortController()
  const timeoutId = setTimeout(() => controller.abort(), timeout)
  
  try {
    const response = await fetch(url, {
      signal: controller.signal
    })
    clearTimeout(timeoutId)
    
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }
    
    return response.json()
  } catch (error) {
    clearTimeout(timeoutId)
    throw error
  }
}

8.6 调试技巧

启用详细日志

tsx 复制代码
import { QueryClient } from '@tanstack/react-query'

const queryClient = new QueryClient({
  logger: {
    log: console.log,
    warn: console.warn,
    error: console.error,
  },
})

使用浏览器开发工具

  1. React Query DevTools: 查看查询状态、缓存数据和网络请求
  2. Network 面板: 监控实际的网络请求
  3. Console 面板: 查看错误信息和调试日志
  4. React DevTools: 检查组件状态和 props

添加调试信息

tsx 复制代码
const { data, error, isError } = useQuery({
  queryKey: ['debug-query'],
  queryFn: async () => {
    console.log('查询开始执行')
    const result = await fetchData()
    console.log('查询结果:', result)
    return result
  },
  onError: (error) => {
    console.error('查询失败:', error)
  },
  onSuccess: (data) => {
    console.log('查询成功:', data)
  }
})

通过以上指南,您应该能够解决大部分在使用 @tanstack/react-query 过程中遇到的问题。如果问题仍然存在,建议查看官方文档或在 GitHub 仓库中提交 issue。

相关推荐
学习同学2 小时前
从0到1制作一个go语言服务器 (一) 配置
服务器·开发语言·golang
袁泽斌的学习记录2 小时前
ubuntu22.04安装cuda11.4版本
linux·运维·服务器
Nan_Shu_6142 小时前
学习:uniapp全栈微信小程序vue3后台(28)
前端·学习·微信小程序·小程序·uni-app
珍宝商店2 小时前
原生 JavaScript 方法实战指南
开发语言·前端·javascript
蓝莓味的口香糖3 小时前
【企业微信】VUE项目在企微中自定义转发内容
前端·vue.js·企业微信
IT_陈寒3 小时前
告别低效!用这5个Python技巧让你的数据处理速度提升300% 🚀
前端·人工智能·后端
—Qeyser3 小时前
Laravel + UniApp AES加密/解密
前端·uni-app·laravel
C++chaofan3 小时前
游标查询在对话历史场景下的独特优势
java·前端·javascript·数据库·spring boot
cg.family3 小时前
Vue3 v-slot 详解与示例
前端·javascript·vue.js