数据请求库:React Query 核心概念

5 阅读2分钟

引言

在现代前端开发中,数据请求管理是一个核心挑战。传统的 useEffect + useState 模式虽然简单,但面临着缓存、重复请求、加载状态管理等诸多问题。React Query(现更名为 TanStack Query)应运而生,成为 React 生态中最流行的服务端状态管理库。

为什么需要 React Query?

在 React 应用中,我们通常将状态分为两类:

  1. 客户端状态:UI 状态,如表单输入、模态框开关等
  2. 服务端状态:从服务器获取的数据,如用户信息、文章列表等

React Query 专注于管理服务端状态,提供以下核心能力:

  • 自动缓存和后台更新
  • 重复请求去重
  • 加载/错误状态管理
  • 分页和无限加载
  • 乐观更新

核心概念

1. Query(查询)

Query 是 React Query 的基础单元,用于获取数据:

import { useQuery } from '@tanstack/react-query'

function UserProfile({ userId }) {
  const { data, isLoading, error } = useQuery({
    queryKey: ['user', userId],
    queryFn: () => fetch(`/api/users/${userId}`).then(res => res.json())
  })
  
  if (isLoading) return <div>加载中...</div>
  if (error) return <div>加载失败</div>
  
  return <div>{data.name}</div>
}

关键点:

  • queryKey:唯一标识查询的数组,用于缓存和失效
  • queryFn:返回 Promise 的函数,用于获取数据

2. Mutation(变更)

Mutation 用于创建、更新或删除数据:

import { useMutation, useQueryClient } from '@tanstack/react-query'

function CreatePost() {
  const queryClient = useQueryClient()
  
  const mutation = useMutation({
    mutationFn: (newPost) => fetch('/api/posts', {
      method: 'POST',
      body: JSON.stringify(newPost)
    }),
    onSuccess: () => {
      // 失效并重新获取帖子列表
      queryClient.invalidateQueries(['posts'])
    }
  })
  
  const handleSubmit = (e) => {
    e.preventDefault()
    mutation.mutate({ title: '新文章', content: '内容...' })
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <button disabled={mutation.isPending}>
        {mutation.isPending ? '提交中...' : '提交'}
      </button>
    </form>
  )
}

3. 缓存策略

React Query 的智能缓存机制:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000,      // 5 分钟内数据新鲜
      gcTime: 10 * 60 * 1000,        // 10 分钟后清理缓存
      retry: 3,                       // 失败重试 3 
      refetchOnWindowFocus: true,    // 窗口聚焦时重新获取
    },
  },
})

4. 依赖查询

处理有依赖关系的查询:

// 只有获取到用户后,才获取用户文章
const { data: user } = useQuery({
  queryKey: ['user', userId],
  queryFn: getUser
})

const { data: posts } = useQuery({
  queryKey: ['posts', userId],
  queryFn: getPosts,
  enabled: !!user  // 用户存在时才执行
})

最佳实践

1. 合理的 Query Key 设计

// ✅ 好的设计
['users', userId, 'posts', postId]
['todos', { status: 'active', page: 1 }]

// ❌ 避免
['data']  // 太笼统
['user-' + userId]  // 应该用数组

2. 错误处理

const { error } = useQuery({
  queryKey: ['user', userId],
  queryFn: fetchUser,
  retry: (failureCount, error) => {
    // 只在 409 错误时重试
    if (error.status === 409) return true
    return false
  }
})

3. 预取数据

// 鼠标悬停时预取
queryClient.prefetchQuery({
  queryKey: ['user', userId],
  queryFn: fetchUser
})

总结

React Query 通过声明式 API 和智能缓存机制,极大简化了服务端状态管理。掌握其核心概念后,你可以:

  • 减少 80% 以上的数据请求代码
  • 自动处理加载、错误、缓存状态
  • 实现更好的用户体验(后台更新、乐观更新)

建议从简单的 query 开始,逐步探索 mutation、无限加载、实时订阅等高级特性。