06. Query/Cache:别把缓存揉成泥

TanStack Router 有 cache,TanStack Query 也有 cache,Cloudflare 还有 CDN cache。它们不是同一个东西。把所有缓存叫“缓存”就像把所有动物叫“肉”,厨房和动物园都会报警。

分工表

适合不适合
Router loader cache路由级关键数据、按 path/search 变化的数据、预加载复杂 mutation、多个路由共享状态、乐观更新
TanStack Query共享 server state、mutation、invalidation、分页/无限列表纯路由守卫、简单一次性页面数据
HTTP/CDN cache公开可缓存响应、边缘缓存用户私有数据、强一致写后读
数据库/应用缓存昂贵查询、跨请求缓存浏览器 UI 状态

Router cache 的特点

export const Route = createFileRoute('/posts/$postId')({
  loader: ({ params }) => fetchPost(params.postId),
  staleTime: 10_000,
  gcTime: 5 * 60_000,
})

什么时候引入 Query?

一旦出现 mutation、乐观更新、跨页面共享、复杂 invalidation,就不要硬靠 Router cache。

const postQueryOptions = (id: string) => queryOptions({
  queryKey: ['post', id],
  queryFn: () => fetchPost(id),
})

export const Route = createFileRoute('/posts/$postId')({
  loader: ({ context, params }) =>
    context.queryClient.ensureQueryData(postQueryOptions(params.postId)),
  component: PostPage,
})

function PostPage() {
  const { postId } = Route.useParams()
  const post = useSuspenseQuery(postQueryOptions(postId)).data
}

Next.js 对照

Next 的缓存模型常与 fetch、RSC、route cache 绑定;TanStack 更鼓励你显式选择缓存层。好处是可追踪,坏处是你不能假装不知道自己在做什么。

快速判断

一个 account 对象被多个 dashboard widget 使用,并会被用户修改。优先用什么?