大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
服务端状态与 TanStack Query
useEffect + fetch 能拉数据,却难处理 缓存、重复请求、后台刷新、乐观更新。TanStack Query(原 React Query)把 服务端状态 当一等公民;Redux 生态里 RTK Query 走类似思路。
学习目标
- 区分客户端状态与服务端状态
- 掌握 Query 的核心概念:queryKey、staleTime、invalidate
- 知道 RTK Query 与 TanStack Query 的选型场景
为何不用 useEffect 包一切
| 问题 | 手写 fetch | TanStack Query |
|---|---|---|
| 同 key 重复请求 | 易重复 | 自动 dedupe |
| 切页回来 | 再 loading | 缓存 + 可选 refetch |
| 错误/加载态 | 每个组件写 | 统一 isLoading / isError |
| 列表增删改 | 手动改 state | invalidateQueries |
react-data 的 fetch 入门仍有效;Query 是 规模化 时的升级。
TanStack Query 基础
import { useQuery, useQueryClient } from "@tanstack/react-query";
function TrackList() {
const { data, isLoading, error } = useQuery({
queryKey: ["tracks"],
queryFn: () => fetch("/api/tracks").then((r) => r.json()),
staleTime: 60_000,
});
if (isLoading) return <p>加载中…</p>;
if (error) return <p>加载失败</p>;
return <ul>{data.map((t) => <li key={t.slug}>{t.title}</li>)}</ul>;
}
queryKey 决定缓存身份:改 slug 就改 key。mutation 成功后:
queryClient.invalidateQueries({ queryKey: ["tracks"] });
staleTime 与 gcTime
- staleTime:多久内视为「新鲜」、不自动 refetch
- gcTime(原 cacheTime):无订阅者后缓存保留多久
课时列表可 staleTime 较长;用户权限宜短或窗口 focus 时 refetch。
RTK Query 简览
已用 Redux 管复杂客户端状态时,RTK Query 把 API slice 与缓存写进 store:
createApi+endpoints定义 REST- 自动生成 hooks:
useGetTracksQuery
| 场景 | 倾向 |
|---|---|
| 无 Redux、Next.js + React | TanStack Query |
| 已有 Redux 大型后台 | RTK Query |
| GraphQL | Apollo Client(下节 GraphQL 课) |
与 Next.js RSC
Server Component 可直接 fetch 带 cache;客户端交互区(收藏、实时筛选)再用 Query。分工见 nextjs-essentials 的 Server/Client 边界。
练习
- 为
/api/tracks写useQuery,staleTime 设 30s,观察切 tab 行为 - 实现一个 mutation 后 invalidate 列表
- 对比 RTK Query 文档首页,写三条与 TanStack Query 的异同
小结
服务端状态 = 缓存 + 失效策略,不是另一个 useState。 下一课 Axios 与 REST 客户端细节。