SSR 和 SvelteKit

设置

SvelteKit 默认使用 SSR 渲染路由。因此,您需要在服务器上禁用查询。否则,即使 HTML 已发送到客户端,您的查询仍将继续在服务器上异步执行。

实现此目的的推荐方法是在 QueryClient 对象中使用 SvelteKit 的 browser 模块。这不会禁用 queryClient.prefetchQuery(),该方法在以下解决方案之一中使用。

src/routes/+layout.svelte

svelte
<script lang="ts">
  import { browser } from '$app/environment'
  import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'

  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })
</script>

<QueryClientProvider client={queryClient}>
  <slot />
</QueryClientProvider>
<script lang="ts">
  import { browser } from '$app/environment'
  import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'

  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })
</script>

<QueryClientProvider client={queryClient}>
  <slot />
</QueryClientProvider>

预取数据

Svelte Query 支持两种在服务器上预取数据并将其传递给 SvelteKit 客户端的方法。

如果您希望查看理想的 SSR 设置,请查看 SSR 示例

使用 initialData

与 SvelteKit 的 load 一起,您可以将服务器端加载的数据传递到 createQueryinitialData 选项中:

src/routes/+page.ts

ts
export async function load() {
  const posts = await getPosts()
  return { posts }
}
export async function load() {
  const posts = await getPosts()
  return { posts }
}

src/routes/+page.svelte

svelte
<script>
  import { createQuery } from '@tanstack/svelte-query'
  import type { PageData } from './$types'

  export let data: PageData

  const query = createQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    initialData: data.posts,
  })
</script>
<script>
  import { createQuery } from '@tanstack/svelte-query'
  import type { PageData } from './$types'

  export let data: PageData

  const query = createQuery({
    queryKey: ['posts'],
    queryFn: getPosts,
    initialData: data.posts,
  })
</script>

优点:

  • 此设置很简单,对于某些情况来说可能是一个快速的解决方案
  • 适用于 +page.ts/+layout.ts+page.server.ts/+layout.server.ts 加载函数

缺点:

  • 如果您在树中更深层的组件中调用 createQuery,则需要将 initialData 向下传递到该点
  • 如果您在多个位置使用相同的查询调用 createQuery,则需要将 initialData 传递给所有这些查询
  • 无法知道查询在服务器上获取的时间,因此 dataUpdatedAt 和确定查询是否需要重新获取是基于页面加载时间而不是

使用 prefetchQuery

Svelte Query 支持在服务器上预取查询。使用下面的此设置,您可以获取数据并在将其发送到用户浏览器之前将其传递到 QueryClientProvider。因此,此数据已在缓存中可用,并且在客户端不会发生初始获取。

src/routes/+layout.ts

ts
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'

export async function load() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })

  return { queryClient }
}
import { browser } from '$app/environment'
import { QueryClient } from '@tanstack/svelte-query'

export async function load() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: {
        enabled: browser,
      },
    },
  })

  return { queryClient }
}

src/routes/+layout.svelte

svelte
<script lang="ts">
  import { QueryClientProvider } from '@tanstack/svelte-query'
  import type { LayoutData } from './$types'

  export let data: LayoutData
</script>

<QueryClientProvider client={data.queryClient}>
  <slot />
</QueryClientProvider>
<script lang="ts">
  import { QueryClientProvider } from '@tanstack/svelte-query'
  import type { LayoutData } from './$types'

  export let data: LayoutData
</script>

<QueryClientProvider client={data.queryClient}>
  <slot />
</QueryClientProvider>

src/routes/+page.ts

ts
export async function load({ parent, fetch }) {
  const { queryClient } = await parent()

  // 您需要在此处使用 SvelteKit fetch 函数
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
}
export async function load({ parent, fetch }) {
  const { queryClient } = await parent()

  // 您需要在此处使用 SvelteKit fetch 函数
  await queryClient.prefetchQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
}

src/routes/+page.svelte

svelte
<script lang="ts">
  import { createQuery } from '@tanstack/svelte-query'

  // 此数据由 +page.ts 中的 prefetchQuery 缓存,因此此处实际上不会发生获取
  const query = createQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
</script>
<script lang="ts">
  import { createQuery } from '@tanstack/svelte-query'

  // 此数据由 +page.ts 中的 prefetchQuery 缓存,因此此处实际上不会发生获取
  const query = createQuery({
    queryKey: ['posts'],
    queryFn: async () => (await fetch('/api/posts')).json(),
  })
</script>

优点:

  • 服务器加载的数据可以在任何地方访问,而无需进行属性钻取
  • 页面渲染后,客户端不会发生初始获取,因为查询缓存保留了有关查询的所有信息,包括 dataUpdatedAt

缺点:

  • 初始设置需要更多文件
  • 不适用于 +page.server.ts/+layout.server.ts 加载函数(但是,与 TanStack Query 一起使用的 API 需要完全暴露给浏览器)