SSR 和 SvelteKit
设置
SvelteKit 默认将在 SSR 编译阶段渲染路由。 出于这一点考虑,你需要在服务器端禁用查询,否则你的查询将在服务器端没有 HTML 内容的情况下异步运行(HTML 已被送至客户端)。
推荐的解决办法是在QueryClient实例中导入 SvelteKit 的browser模块。
这并不会禁用queryClient.prefetchQuery(),因为它涉及到如何预取数据:
src/routes/+layout.svelte
Markdown
1<script lang="ts">2 import { browser } from '$app/environment'3 import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'4 5 const queryClient = new QueryClient({6 defaultOptions: {7 queries: {8 enabled: browser,9 },10 },11 })12</script>1314<QueryClientProvider client={queryClient}>15 <slot />16</QueryClientProvider>预取数据
Svelte Query 支持两种将服务器端预取的数据传输到客户端的方法。
如果你希望有更为详尽的解释,希望有点代码可用,请查看 SSR 的入门例子.
使用 initialData
组合 SvelteKit 的 load特性,你可以将预取的数据在服务器端传输给createQuery的initialData选项:
src/routes/+page.ts
TypeScript
1import type { PageLoad } from "./$types";2 3export const load: PageLoad = async () => {4 const posts = await getPosts();5 return { posts };6};src/routes/+page.svelte
Markdown
1<script>2 import { createQuery } from '@tanstack/svelte-query'3 import type { PageData } from './$types'4 5 export let data: PageData6 7 const query = createQuery({8 queryKey: ['posts'],9 queryFn: getPosts,10 initialData: data.posts11 })12</script>优点:
- 这种方式是最小化的,且这是对于常用场景的最快的方法
- 和
+page.ts/+layout.ts以及+page.server.ts/+layout.server.ts的 load 函数无任何冲突
缺点:
- 如果你在组件树的某个组件调用
createQuery函数,你必须将initialData透传过去 - 如果你通过
createQuery创建的查询在多个地方被调用,你必须将initialData透传给每一个查询 - 查询在服务器端预取的准确时间是无法获知的,所以
dataUpdatedAt和其他关于重新获取的逻辑都依赖于页面何时被加载
使用 prefetchQuery
Svelte Query 支持在服务器端通过查询预取数据。 使用下面的设置,你可以早在数据送到客户端之前提前查询。 因此,这些数据已被标记为缓存对象,不能从客户端初始化:
src/routes/+layout.ts
TypeScript
1import { browser } from "$app/environment";2import { QueryClient } from "@tanstack/svelte-query";3import type { LayoutLoad } from "./$types";4 5export const load: LayoutLoad = async () => {6 const queryClient = new QueryClient({7 defaultOptions: {8 queries: {9 enabled: browser,10 },11 },12 });13 14 return { queryClient };15};src/routes/+layout.svelte
Markdown
1<script lang="ts">2 import { QueryClientProvider } from '@tanstack/svelte-query'3 import type { LayoutData } from './$types'4 5 export let data: LayoutData6</script>7 8<QueryClientProvider client={data.queryClient}>9 <slot />10</QueryClientProvider>src/routes/+page.ts
TypeScript
1import type { PageLoad } from "./$types";2 3export const load: PageLoad = async ({ parent, fetch }) => {4 const { queryClient } = await parent();5 6 // 你需要使用 SvelteKit 的 fetch 函数7 await queryClient.prefetchQuery({8 queryKey: ["posts"],9 queryFn: async () => (await fetch("/api/posts")).json(),10 });11};src/routes/+page.svelte
Markdown
1<script lang="ts">2 import { createQuery } from '@tanstack/svelte-query'3 4 // 这个数据被 prefetchQuery 缓存在 +page.ts 里,所以(客户端)没有任何真实的查询被触发5 const query = createQuery({6 queryKey: ['posts'],7 queryFn: async () => (await fetch('/api/posts')).json(),8 })9</script>优点:
- 服务器端的数据不需要任何形式的透传,可以被任何地方随意访问
- 在客户端页面渲染时没有初始化请求负载,因为缓存已经知悉了所有有关查询的信息,包括
dataUpdatedAt
缺点:
- 需要更为复杂的设置
- 无法和
+page.server.ts/+layout.server.ts的 load 函数一起使用 (并且,无论如何,与 Svelte Query 一起使用的 API 都需要完全暴露给浏览器)