用途
该技能用于指导在服务端渲染(SSR)场景下正确使用 TanStack Query,涉及意图、生命周期、dehydrate、hydrate、HydrationBoundary,以及 TanStack Start、TanStack Router 的 SSR Query 集成、Next.js App Router 与 Next.js Pages Router 等框架。目标是让服务端预取的数据能够正确注水(hydrate)到客户端缓存,避免重复请求与数据不同步。
主要能力
- 使用 dehydrate 与 HydrationBoundary 将服务端预取的数据传递到客户端。
- 通过 prefetchQuery 在服务端预取数据,再由 HydrationBoundary 注水。
- 在 TanStack Start 与 TanStack Router 中通过 setupRouterSsrQueryIntegration 集成 SSR Query。
- 为每个请求创建独立的 QueryClient(per-request clients)。
- 仅注水已预取的数据。
- 识别并规避常见错误,例如 RSC 中重复渲染已获取数据、Suspense 查询未在服务端预取、SvelteKit 查询在 SSR 响应后执行等。
使用方式
基础设置示例:
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query'
export async function PostsPage() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: async () => [{ id: 1 }],
})
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<main>Posts</main>
</HydrationBoundary>
)
}
TanStack Start 与 Router 优先集成:
import { QueryClient } from '@tanstack/react-query'
import { createRouter } from '@tanstack/react-router'
import { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'
import { routeTree } from './routeTree.gen'
const queryClient = new QueryClient()
const router = createRouter({ routeTree, context: { queryClient } })
setupRouterSsrQueryIntegration({ router, queryClient })
按请求创建客户端:
import { QueryClient } from '@tanstack/react-query'
export function createSsrQueryClient() {
return new QueryClient({
defaultOptions: { queries: { staleTime: 60_000 } },
})
}
仅注水已预取数据:
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query'
export async function Page() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['profile'],
queryFn: async () => ({ name: 'Tanner' }),
})
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<main>Profile</main>
</HydrationBoundary>
)
}
常见错误
严重:RSC 重复渲染已获取数据
错误写法:
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query'
export async function Page() {
const queryClient = new QueryClient()
const posts = await queryClient.fetchQuery({
queryKey: ['posts'],
queryFn: async () => [{ id: 1 }],
})
return (
<>
<p>{posts.length}</p>
<HydrationBoundary state={dehydrate(queryClient)}>
<main>Posts</main>
</HydrationBoundary>
</>
)
}
正确写法:
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query'
export async function Page() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: async () => [{ id: 1 }],
})
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<main>Posts</main>
</HydrationBoundary>
)
}
服务端渲染的派生数据可能与客户端重新获取的 Query 数据不同步。
来源:TanStack/query:docs/framework/react/guides/advanced-ssr.md
严重:Suspense 查询未在服务端预取
错误写法:
import { useSuspenseQuery } from '@tanstack/react-query'
export function Posts() {
const { data } = useSuspenseQuery({
queryKey: ['posts'],
queryFn: async () => [{ id: 1 }],
})
return <pre>{JSON.stringify(data)}</pre>
}
正确写法:
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query'
export async function Page() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: async () => [{ id: 1 }],
})
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<main>Posts</main>
</HydrationBoundary>
)
}
未预取的 Suspense 查询可能在服务端发起请求、注水失败,然后在客户端再次请求。
来源:TanStack/query:docs/framework/react/guides/ssr.md
高:SvelteKit 查询在 SSR 响应后执行
错误写法:
import { QueryClient } from '@tanstack/svelte-query'
export const queryClient = new QueryClient()
正确写法:
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'
export const queryClient = new QueryClient({
defaultOptions: { queries: { enabled: browser } },
})
除非显式预取服务端数据,SvelteKit SSR 需要通过 browser 门控默认查询执行。
来源:TanStack/query:docs/framework/svelte/ssr.md
另见:compositions/compose-query-with-tanstack-router-and-start,用于 TanStack 自有的 SSR 路由。
适用场景
- 使用 Next.js App Router 或 Pages Router 并需要服务端预取数据。
- 使用 TanStack Start 或 TanStack Router 并需要 SSR Query 集成。
- 使用 SvelteKit 并需要控制查询在服务端与客户端的执行时机。
- 需要在服务端预取数据后通过 HydrationBoundary 注水到客户端缓存。
限制
资料未提供该技能的具体安装命令、收费方式、价格、平台支持范围或效果数据,这些信息暂未提供。