TanStack Query 入门:服务端状态管理的现代答案
TanStack Query 消灭数据获取样板代码:智能缓存、后台刷新、乐观更新。本文讲解查询状态模型、缓存配置与变更实战。
TanStack Query 把"请求-加载-错误-缓存"四件套收进一个 Hook:useQuery({ queryKey, queryFn }) 自动处理加载态、缓存、去重与后台刷新;useMutation 管写操作。它不是状态管理器,是"服务端状态"的专用引擎。
为什么需要它
手写数据获取的典型样板:useState 存数据/loading/error + useEffect 发请求 + 处理竞态 + 缓存逻辑——每处几十行。TanStack Query 的认识:服务端数据不是前端状态——它是需要同步的远程缓存,有专门的语义(过期、刷新、失效)。
快速上手
npm install @tanstack/react-query
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>...</QueryClientProvider>
function Users() {
const { data, isLoading, error } = useQuery({
queryKey: ['users'],
queryFn: () => fetch('/api/users').then(r => r.json()),
staleTime: 60_000, // 1 分钟内视为新鲜,不重复请求
});
if (isLoading) return <Spinner />;
return <ul>{data.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
}
查询状态与缓存机制
- queryKey 是缓存的键:
['users', { page: 2 }]——参数变化自动成为新缓存条目; - staleTime:数据保鲜期——期内切回页面零请求;
- 后台刷新:数据过期后自动 refetch,用户无感更新;
- 请求去重:同一 key 的并发请求自动合并。
变更与乐观更新
const mutation = useMutation({
mutationFn: (newUser) => api.createUser(newUser),
onMutate: async (newUser) => {
await queryClient.cancelQueries({ queryKey: ['users'] });
const previous = queryClient.getQueryData(['users']);
queryClient.setQueryData(['users'], old => [...old, newUser]); // 乐观更新
return { previous };
},
onError: (err, vars, ctx) => queryClient.setQueryData(['users'], ctx.previous), // 回滚
onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), // 最终同步
});
乐观更新三件套:立即更新 UI → 失败回滚 → 结束后重新校验——体验与正确性兼得。
用真实访问验证前端表现
TanStack Query 入门中的开发期结果,还需要放到真实访问场景中验证。观测云 Web RUM 可采集页面、资源请求和前端错误;应在浏览器入口初始化,并为每次发布设置一致的环境与版本。错误堆栈还原需要上传匹配的 SourceMap,不能仅打开构建选项就认为平台已收到映射文件。
接入文档:Web RUM 接入 · SourceMap 配置。
常见问题(FAQ)
Q:有了它还需要 Zustand/Redux 吗?
需要但分工明确:TanStack Query 管服务端状态(远程数据),Zustand 等管客户端状态(UI 状态、本地草稿)。多数应用的服务端状态占大头——引入 Query 后全局状态库的规模大幅缩水。
Q:轮询与实时更新怎么实现?
refetchInterval 配置轮询;WebSocket 场景在消息回调中 invalidateQueries 让缓存失效重取。
Q:支持非 React 框架吗?
TanStack Query 有 Vue/Svelte/Solid/Angular 版本——核心引擎框架无关。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。