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

persistQueryClient

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

这是一组用于与“持久化器”(persisters)交互的工具,这些持久化器可将你的 queryClient 保存下来供后续使用。你可以使用不同的 持久化器 将客户端及缓存存储到多种不同的存储层中。

构建持久化器

工作原理

重要提示:为使持久化功能正常工作,你很可能需要向 QueryClient 传入一个 gcTime 值,以在注水(hydration)期间覆盖默认值(如上所示)。

若在创建 QueryClient 实例时未设置该值,则其默认为 300000(5 分钟)用于注水,且存储的缓存将在 5 分钟无活动后被丢弃。这是默认的垃圾回收行为。

该值应设为与 persistQueryClient 的 maxAge 选项相同或更高。例如,若 maxAge 为 24 小时(默认值),则 gcTime 应设为 24 小时或更高。若低于 maxAge,垃圾回收机制将提前触发,导致缓存比预期更早被丢弃。

你也可以传入 Infinity 来完全禁用垃圾回收行为。

受 JavaScript 限制,允许的最大 gcTime 值约为 24 天,但可通过 timeoutManager.setTimeoutProvider 绕过此限制。

TypeScript
1const queryClient = new QueryClient({2  defaultOptions: {3    queries: {4      gcTime: 24 * 60 * 60 * 1000, // 24 hours5    },6  },7})

缓存失效(Cache Busting)

有时,你可能会对应用或数据做出变更,从而立即使所有已缓存数据失效。一旦发生这种情况,你可以传入一个 buster 字符串选项。若找到的缓存不包含该失效字符串,则会被丢弃。以下多个函数均接受此选项:

TypeScript
1persistQueryClient({ queryClient, persister, buster: buildHash })2persistQueryClientSave({ queryClient, persister, buster: buildHash })3persistQueryClientRestore({ queryClient, persister, buster: buildHash })

移除

若发现数据属于下列任一情况:

  1. 已过期(参见 maxAge)
  2. 已失效(参见 buster)
  3. 出错(例如:throws ...)
  4. 为空(例如:undefined)

则会调用持久化器的 removeClient() 方法,缓存将被立即丢弃。

API

persistQueryClientSave

  • 你的查询(query)/修改(mutation)将被 dehydrated 并由你提供的持久化器存储。
  • createSyncStoragePersister 和 createAsyncStoragePersister 对该操作进行节流,确保每秒最多执行一次,以避免频繁写入带来的开销。请查阅其文档了解如何自定义节流时间。

你可以使用它在你选定的时刻显式地持久化缓存。

TypeScript
1persistQueryClientSave({2  queryClient,3  persister,4  buster = '',5  dehydrateOptions = undefined,6})

persistQueryClientSubscribe

每当你的 queryClient 缓存发生变化时,即运行 persistQueryClientSave。例如:你可能在用户登录并勾选“记住我”时启动 subscribe。

  • 它返回一个 unsubscribe 函数,可用于停止监控,从而终止对持久化缓存的更新。
  • 若你想在 unsubscribe 后清除已持久化的缓存,可向 persistQueryClientRestore 传入一个新的 buster,这将触发持久化器的 removeClient 方法并丢弃已持久化的缓存。
TypeScript
1persistQueryClientSubscribe({2  queryClient,3  persister,4  buster = '',5  dehydrateOptions = undefined,6})

persistQueryClientRestore

  • 尝试从持久化器中 hydrate 之前已持久化的脱水(dehydrated)查询/修改缓存,并将其还原至所传入 query client 的查询缓存中。
  • 若找到的缓存早于 maxAge(默认为 24 小时),则会被丢弃。该时限可根据需要自定义。

你可以使用它在你选定的时刻恢复缓存。

TypeScript
1persistQueryClientRestore({2  queryClient,3  persister,4  maxAge = 24 * 60 * 60 * 1000, // 24 hours5  buster = '',6  hydrateOptions = undefined,7})

persistQueryClient

执行以下操作:

  1. 立即恢复任何已持久化的缓存(参见 persistQueryClientRestore)
  2. 订阅查询缓存,并返回 unsubscribe 函数(参见 persistQueryClientSubscribe)。

此功能继承自 3.x 版本。

TypeScript
1persistQueryClient({2  queryClient,3  persister,4  maxAge = 24 * 60 * 60 * 1000, // 24 hours5  buster = '',6  hydrateOptions = undefined,7  dehydrateOptions = undefined,8})

Options

所有可用选项如下:

TypeScript
1interface PersistQueryClientOptions {2  /** The QueryClient to persist */3  queryClient: QueryClient4  /** The Persister interface for storing and restoring the cache5   * to/from a persisted location */6  persister: Persister7  /** The max-allowed age of the cache in milliseconds.8   * If a persisted cache is found that is older than this9   * time, it will be **silently** discarded10   * (defaults to 24 hours) */11  maxAge?: number12  /** A unique string that can be used to forcefully13   * invalidate existing caches if they do not share the same buster string */14  buster?: string15  /** The options passed to the hydrate function16   * Not used on `persistQueryClientSave` or `persistQueryClientSubscribe` */17  hydrateOptions?: HydrateOptions18  /** The options passed to the dehydrate function19   * Not used on `persistQueryClientRestore` */20  dehydrateOptions?: DehydrateOptions21}

实际上提供了三个接口:

  • PersistedQueryClientSaveOptions 用于 persistQueryClientSave 和 persistQueryClientSubscribe(不使用 hydrateOptions)。
  • PersistedQueryClientRestoreOptions 用于 persistQueryClientRestore(不使用 dehydrateOptions)。
  • PersistQueryClientOptions 用于 persistQueryClient

在 Preact 中使用

persistQueryClient 将尝试恢复缓存,并自动订阅后续变更,从而将你的客户端与所提供的存储同步。

但恢复是异步的,因为所有持久化器本质上都是异步的。这意味着,若你在恢复过程中渲染 App,而某个查询恰好在此时挂载并发起拉取,则可能引发竞态条件。

此外,若你在 Preact 组件生命周期之外订阅变更,则无法取消订阅:

TypeScript
1// 🚨 never unsubscribes from syncing2persistQueryClient({3  queryClient,4  persister: localStoragePersister,5})6 7// 🚨 happens at the same time as restoring8PreactDOM.createRoot(rootElement).render(<App />)

PersistQueryClientProvider

针对此场景,你可以使用 PersistQueryClientProvider。它将确保根据 Preact 组件生命周期正确执行订阅与取消订阅,并确保在恢复完成前,查询不会开始拉取。查询仍会正常渲染,但会处于 fetchingState: 'idle' 状态,直至数据恢复完成。之后,除非恢复的数据足够 新鲜(fresh),否则将重新拉取;同时也会尊重 initialData。它可替代常规的 QueryClientProvider 使用:

TypeScript
1import { PersistQueryClientProvider } from '@tanstack/preact-query-persist-client'2import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'3 4const queryClient = new QueryClient({5  defaultOptions: {6    queries: {7      gcTime: 24 * 60 * 60 * 1000, // 24 hours8    },9  },10})11 12const persister = createAsyncStoragePersister({13  storage: window.localStorage,14})15 16PreactDOM.createRoot(rootElement).render(17  <PersistQueryClientProvider18    client={queryClient}19    persistOptions={{ persister }}20  >21    <App />22  </PersistQueryClientProvider>,23)

属性(Props)

PersistQueryClientProvider 接收与 QueryClientProvider 相同的属性,并额外支持:

  • persistOptions: PersistQueryClientOptions
  • onSuccess?: () => Promise<unknown> | unknown
    • 可选
    • 初始恢复完成后调用
    • 可用于 resumePausedMutations
    • 若返回 Promise,则会等待其完成;在此期间,恢复过程被视为仍在进行中
  • onError?: () => Promise<unknown> | unknown
    • 可选
    • 恢复过程中抛出错误时调用
    • 若返回 Promise,则会等待其完成

useIsRestoring

若你正在使用 PersistQueryClientProvider,还可配合使用 useIsRestoring Hook 来检查当前是否正在进行恢复。useQuery 及其相关方法内部也检查此状态,以避免恢复过程与挂载查询之间的竞态条件。

持久化器(Persisters)

持久化器接口

持久化器具有以下接口:

TypeScript
1export interface Persister {2  persistClient(persistClient: PersistedClient): Promisable<void>3  restoreClient(): Promisable<PersistedClient | undefined>4  removeClient(): Promisable<void>5}

已持久化的客户端条目具有以下接口:

TypeScript
1export interface PersistedClient {2  timestamp: number3  buster: string4  clientState: DehydratedState5}

你可以导入这些类型(用于构建持久化器):

TypeScript
1import {2  PersistedClient,3  Persister,4} from '@tanstack/preact-query-persist-client'

构建持久化器

你可以按需实现任意持久化方式。以下是一个构建 Indexed DB 持久化器的示例。相比 Web Storage API,Indexed DB 更快、可存储超过 5MB 数据,且无需序列化。这意味着它可直接存储 JavaScript 原生类型,例如 Date 和 File。

TypeScript
1import { get, set, del } from 'idb-keyval'2import {3  PersistedClient,4  Persister,5} from '@tanstack/preact-query-persist-client'6 7/**8 * Creates an Indexed DB persister9 * @see https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API10 */11export function createIDBPersister(idbValidKey: IDBValidKey = 'reactQuery') {12  return {13    persistClient: async (client: PersistedClient) => {14      await set(idbValidKey, client)15    },16    restoreClient: async () => {17      return await get<PersistedClient>(idbValidKey)18    },19    removeClient: async () => {20      await del(idbValidKey)21    },22  } satisfies Persister23}

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

译自上游 59d11de