目录 (Outline)
- 一、 从 useEffect 到 React Query:为什么状态管理需要解耦?
- 二、 TanStack Query v5 核心:简化、一致与性能
- 三、 快速上手:构建一个带自动重试与缓存的列表页
- 四、 核心机制:查询键 (Query Keys) 与缓存失效 (Invalidation)
- 五、 实战 1:利用 useMutation 实现乐观更新 (Optimistic Updates)
- 六、 实战 2:Infinite Queries——轻松实现无限滚动与分页
- 七、 进阶:Hydration 与 SSR 支持(Vite 6 场景)
- 八、 总结:TanStack Query 带来的异步编程新范式
一、 从 useEffect 到 React Query:为什么状态管理需要解耦?
1. 历史局限
过去,我们通常在 useEffect 中手动管理数据:
useEffect(() => {
setIsLoading(true);
fetchData().then(data => {
setData(data);
setIsLoading(false);
}).catch(err => setError(err));
}, []);
- 重复请求:多个组件同时加载时,会发起多次请求。
- 状态混乱:加载中、错误处理、数据同步逻辑散落在各处。
- 缓存缺失:没有全局的缓存层,每次进入页面都要重新加载。
2. 标志性事件
- 2020 年:React Query 1.0 发布,引入了「Server State」的概念。
- 2024 年:TanStack Query v5 正式发布,统一了多框架支持,并大幅简化了 API。
二、 TanStack Query v5 核心:简化、一致与性能
v5 版本最大的改变是:单一对象参数。
核心改进
- API 统一:不再支持多参数重载,强制使用对象形式。
- 性能优化:底层算法重构,大幅减少了不必要的重绘。
- Suspense 支持:原生支持 React 18+ 的 Suspense 模式。
三、 快速上手:构建一个带自动重试与缓存的列表页
代码示例
import { useQuery } from '@tanstack/react-query'
function UserList() {
const { data, isLoading, isError, error } = useQuery({
queryKey: ['users'], // 查询键
queryFn: fetchUsers, // 异步函数
staleTime: 1000 * 60 * 5, // 数据 5 分钟内不过期
retry: 3, // 失败自动重试 3 次
})
if (isLoading) return <div>Loading...</div>
if (isError) return <div>Error: {error.message}</div>
return (
<ul>
{data.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
)
}
四、 核心机制:查询键 (Query Keys) 与缓存失效 (Invalidation)
查询键是 TanStack Query 的核心。
- 数组结构:
['users', userId]。 - 自动触发:当数组中的任何一个元素改变时,Query 都会自动重新执行。
- 失效管理:通过
queryClient.invalidateQueries({ queryKey: ['users'] }),你可以手动让相关缓存失效并触发背景更新。
五、 实战 1:利用 useMutation 实现乐观更新 (Optimistic Updates)
乐观更新是提升用户体验的绝佳手段:在请求返回前,先假设成功并更新 UI。
实现代码
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// 1. 取消正在进行的请求
await queryClient.cancelQueries({ queryKey: ['todos'] })
// 2. 备份当前数据
const previousTodos = queryClient.getQueryData(['todos'])
// 3. 乐观更新
queryClient.setQueryData(['todos'], (old) => [...old, newTodo])
return { previousTodos }
},
onError: (err, newTodo, context) => {
// 失败回滚
queryClient.setQueryData(['todos'], context.previousTodos)
},
onSettled: () => {
// 无论成功失败,最后重新同步一次
queryClient.invalidateQueries({ queryKey: ['todos'] })
}
})
六、 实战 2:Infinite Queries——轻松实现无限滚动与分页
useInfiniteQuery 完美解决了加载更多的场景。
- 它自动维护了
pages数组。 - 支持
getNextPageParam和fetchNextPage。
七、 进阶:Hydration 与 SSR 支持(Vite 6 场景)
在服务端渲染(SSR)中,我们可以预取数据并将其序列化。
- Prefetching:在服务端执行
queryClient.prefetchQuery。 - Dehydrate:将状态提取为 JSON 字符串。
- Hydrate:在客户端注入状态,实现「零白屏」的首屏加载。
八、 总结:TanStack Query 带来的异步编程新范式
TanStack Query 已经成为了 React 生态的事实标准。它不仅是一个库,更是一种思维方式:将复杂的服务器状态从本地 UI 状态中剥离出来。掌握了它,你的全栈开发效率将得到质的飞跃。