译零 TransZero · TanStack Query 中文文档
主站

服务端渲染与注水

更新于 2026-11-02 Lit 查看英文原文 ↗

Lit Query 可通过将 Lit SSR 与从 @tanstack/lit-query 重新导出的 TanStack Query Core 注水(hydration)API 结合,实现服务端渲染(server rendering)。

本指南的可运行源码见 SSR 示例。

流程

服务端渲染包含三个阶段:

  1. 为每次请求创建一个独立的 QueryClient。
  2. 在服务端预取(prefetch)查询,并使用该客户端渲染 Lit HTML。
  3. 将缓存脱水(dehydrate)为 HTML,然后在客户端应用渲染前,对浏览器端的 QueryClient 执行注水(hydrate)。

切勿在用户或请求之间共享同一个服务端 QueryClient。

服务端预取与渲染

TypeScript
1import { render } from '@lit-labs/ssr'2import { collectResult } from '@lit-labs/ssr/lib/render-result.js'3import { html } from 'lit'4import { QueryClient, dehydrate, noop } from '@tanstack/lit-query'5import { dataQueries } from './services/data/queries.js'6import './app.js'7 8async function renderPage() {9  const apiBaseUrl = 'https://example.com'10  const queryClient = new QueryClient({11    defaultOptions: {12      queries: {13        staleTime: 30 * 1000,14      },15    },16  })17 18  await queryClient.query(dataQueries.detail(apiBaseUrl)).catch(noop)19 20  const appHtml = await collectResult(21    render(22      html`<ssr-app23        api-base-url=${apiBaseUrl}24        .queryClient=${queryClient}25      ></ssr-app>`,26    ),27  )28 29  const dehydratedState = dehydrate(queryClient)30 31  return { appHtml, dehydratedState }32}

服务端通过属性绑定将相同的客户端传入 Lit 组件。这使得 createQueryController 能在服务端渲染期间读取已预取的缓存。若你的查询函数在服务端渲染(SSR)期间调用 fetch,请传入绝对 API 地址,而非依赖浏览器相对 URL。

客户端注水

TypeScript
1import '@lit-labs/ssr-client/lit-element-hydrate-support.js'2import { QueryClient, hydrate } from '@tanstack/lit-query'3import type { DehydratedState } from '@tanstack/lit-query'4 5const queryClient = new QueryClient({6  defaultOptions: {7    queries: {8      staleTime: 30 * 1000,9    },10  },11})12 13const dehydratedState = JSON.parse(14  document.getElementById('__QUERY_STATE__')?.textContent ?? 'null',15) as DehydratedState16 17queryClient.mount()18hydrate(queryClient, dehydratedState)19 20const appElement = document.querySelector('ssr-app') as21  | (HTMLElement & { queryClient?: QueryClient })22  | null23 24if (!appElement) {25  throw new Error('Expected the SSR app element to exist before hydration.')26}27 28appElement.queryClient = queryClient29await import('./app.js')

若你手动挂载了客户端,请在页面卸载时将其卸载:

TypeScript
1window.addEventListener(2  'pagehide',3  () => {4    queryClient.unmount()5  },6  { once: true },7)

组件模式

SSR 示例仅在 queryClient 属性可用后才创建其控制器:

TypeScript
1import { LitElement } from 'lit'2import { createQueryController } from '@tanstack/lit-query'3import { dataQueries } from './services/data/queries.js'4import type { QueryClient, QueryResultAccessor } from '@tanstack/lit-query'5import type { DataResponse } from './services/data/types.js'6 7class SsrApp extends LitElement {8  static properties = {9    apiBaseUrl: { attribute: 'api-base-url' },10    queryClient: { attribute: false },11  }12 13  apiBaseUrl = ''14  queryClient?: QueryClient15  private dataQuery?: QueryResultAccessor<DataResponse, Error>16 17  protected override willUpdate(): void {18    if (!this.dataQuery && this.queryClient) {19      this.dataQuery = createQueryController(20        this,21        dataQueries.detail(this.apiBaseUrl),22        this.queryClient,23      )24    }25  }26}

这种显式客户端(explicit-client)模式适用于 SSR,因为客户端由渲染器创建,而非从已连接的 DOM 提供者中自动发现。

序列化

将脱水后的状态以 JSON 格式嵌入 HTML,并转义可能破坏 script 标签的字符。示例服务端在替换构建后的 HTML 模板中的 __QUERY_STATE_JSON__ 前,先使用了一个轻量级序列化器。

Lit Query 从 TanStack Query Core 重新导出了 dehydrate 和 hydrate。在服务端完成预取后,使用 dehydrate(queryClient) 捕获缓存状态。在浏览器端,解析该状态、创建一个新的 QueryClient、调用 hydrate(queryClient, dehydratedState)、将客户端赋值给服务端渲染的组件,然后才导入 Lit 组件,使其在具备预取缓存的前提下完成升级。

本页为 TanStack Query 文档(Lit 版)的非官方中文翻译,原文由上游团队维护,遵循 MIT 许可。 译文如有偏差,以英文原文为准。

译自上游 59d11de