引言
在现代前端开发中,数据请求管理是一个核心挑战。传统的 useEffect + useState 模式虽然简单,但面临着缓存、重复请求、加载状态管理等诸多问题。React Query(现更名为 TanStack Query)应运而生,成为 React 生态中最流行的服务端状态管理库。
为什么需要 React Query?
在 React 应用中,我们通常将状态分为两类:
- 客户端状态:UI 状态,如表单输入、模态框开关等
- 服务端状态:从服务器获取的数据,如用户信息、文章列表等
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、无限加载、实时订阅等高级特性。