Skip to main content

persistQueryClient

这是一组用于与"persisters"(用于将queryClient保存以供以后使用的工具)进行交互的实用程序。可以使用不同的persisters将客户端和缓存存储到许多不同的存储层中。

构建 Persisters

createSyncStoragePersister

createAsyncStoragePersister

创建自定义的 persister

工作原理

重要提示 - 为了使 persist 正常工作,您可能希望在hydration 期间为 QueryClient 传递一个 cacheTime 值,以覆盖默认值(如上所示)。

如果在创建 QueryClient 实例时未设置它,它将默认为300000(5分钟)以进行hydration,并且在5分钟不活动后存储的缓存将被丢弃。这是默认的垃圾回收行为。

它应该设置为与persistQueryClient的maxAge选项相同或更高的值。例如,如果maxAge为24小时(默认值),则cacheTime应为24小时或更长。如果低于maxAge,垃圾回收将启动并在预期之前丢弃存储的缓存。

您还可以将其设置为Infinity以完全禁用垃圾回收行为。

const queryClient = new QueryClient({
defaultOptions: {
queries: {
cacheTime: 1000 *60* 60 * 24, // 24小时
},
},
})

缓存破坏

有时,您可能会对应用程序或数据进行更改,这些更改会立即使任何缓存的数据无效。如果发生这种情况,您可以传递buster字符串选项。如果找到的缓存没有该buster字符串,它将被丢弃。以下几个函数接受此选项:

persistQueryClient({ queryClient,persister,buster:buildHash })
persistQueryClientSave({ queryClient,persister,buster:buildHash })
persistQueryClientRestore({ queryClient,persister,buster:buildHash })

删除

如果发现数据属于以下任何一种情况:

  • 已过期(请参阅 maxAge)
  • 已损坏(请参阅 buster)
  • 错误(例如:throws...)
  • 为空(例如:undefined)

persister removeClient() 将被调用,并且缓存将立即被丢弃。

API persistQueryClientSave

通过提供的 persister 将您的查询/更改进行 dehydrated 化并存储。

createSyncStoragePersistercreateAsyncStoragePersister 以最多每1秒的频率执行此操作,以节省潜在昂贵的写操作。查看其文档以了解如何自定义其节流时间。

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

persistQueryClientSave({
queryClient,
persister,
buster = ''
dehydrateOptions = undefined
})

persistQueryClientSubscribe

在您的 queryClient 的缓存更改时运行persistQueryClientSave。例如:当用户登录并选中“记住我”时,您可以启动订阅。

  • 它返回一个取消订阅的函数,您可以使用它来停止对持久化缓存的更新。
  • 如果您想在取消订阅后清除持久化缓存,可以向persistQueryClientRestore发送一个新的buster,这将触发persister的removeClient函数并丢弃持久化缓存。
persistQueryClientSubscribe({
queryClient,
persister,
buster = '',
dehydrateOptions = undefined,
})

persistQueryClientRestore

  • 尝试将先前持久化的去水化查询/突变缓存从persister恢复到传递的查询客户端的查询缓存中。
  • 如果找到的缓存早于maxAge(默认为24小时),它将被丢弃。可以根据需要自定义此时机。

您可以在选择的时刻使用它来恢复缓存。

persistQueryClientRestore({
queryClient,
persister,
maxAge = 1000 *60* 60 * 24, // 24小时
buster = '',
hydrateOptions = undefined,
})

persistQueryClientSave

执行以下操作:

  • 立即恢复任何已持久化的缓存(参见persistQueryClientRestore)
  • 订阅查询缓存并返回取消订阅的函数(参见persistQueryClientSubscribe)。

此功能从3.x版本中保留。

persistQueryClient({
queryClient,
persister,
maxAge = 1000 *60* 60 * 24, // 24小时
buster = '',
hydrateOptions = undefined,
dehydrateOptions = undefined,
})

Options

所有可用选项如下:

interface PersistQueryClientOptions {
/** 要持久化的QueryClient */
queryClient: QueryClient

/** 用于存储和恢复缓存到/从持久化位置的Persister接口*/
persister: Persister

/* 缓存的最长允许年龄(以毫秒为单位)。
如果找到的持久化缓存早于此时间,它将静默丢弃
(默认为24小时) */
maxAge?: number

/* 一个唯一字符串,可用于强制
如果现有缓存与其不共享相同的buster字符串,则使其无效 */
buster?: string

/* 传递给hydrate函数的选项
不用于'persistQueryClientSave'或'persistQueryClientSubscribe' */
hydrateOptions?: HydrateOptions

/* 传递给dehydrate函数的选项
不用于'persistQueryClientRestore' */
dehydrateOptions?: DehydrateOptions
}

实际上有三个可用的接口:

  • PersistedQueryClientSaveOptions 用于persistQueryClientSavepersistQueryClientSubscribe(不要用hydrateOptions)。
  • PersistedQueryClientRestoreOptions 用于persistQueryClientRestore(不要用dehydrateOptions)。
  • PersistQueryClientOptions 用于persistQueryClient

和 React 一起使用

persistQueryClient 将尝试恢复缓存并自动订阅进一步的更改,从而将您的客户端与提供的存储同步。

然而,恢复过程是异步的,因为所有的persisters都是异步的,这意味着如果在恢复过程中渲染您的应用程序,如果查询在同时挂载和获取数据,可能会出现竞争条件。

此外,如果您在React组件生命周期外订阅更改,您无法取消订阅:

// 🚨永远不会取消订阅同步
persistQueryClient({
queryClient,
persister: localStoragePersister,
})

// 🚨与恢复同时发生
ReactDOM.createRoot(rootElement).render(<App />)

PersistQueryClientProvider

对于这种用例,您可以使用PersistQueryClientProvider。它将确保根据React组件生命周期正确订阅/取消订阅,并且还将确保在我们仍在恢复过程中时,查询不会开始获取。查询仍然会渲染,只是它们会被放在fetchingState: 'idle'中,直到数据恢复完成。然后,它们将重新获取数据,除非恢复的数据足够新,并且还将尊重initialData。它可以代替普通的QueryClientProvider

import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client'
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister'

const queryClient = new QueryClient({
defaultOptions: {
queries: {
cacheTime: 1000 *60* 60 * 24, // 24小时
},
},
})

const persister = createSyncStoragePersister({
storage: window.localStorage,
})

ReactDOM.createRoot(rootElement).render(
<PersistQueryClientProvider
client={queryClient}
persistOptions={{ persister }}
>
<App />
</PersistQueryClientProvider>
)

Props

PersistQueryClientProvider 接受与QueryClientProvider 相同的props,以及:

  • persistOptions: PersistQueryClientOptions
    • 您可以传递给persistQueryClient的所有选项,除了QueryClient本身
  • onSuccess?:()=> void

useIsRestoring

如果您使用 PersistQueryClientProvider,您还可以与之一起使用useIsRestoring hook来检查当前是否正在进行恢复。useQuery等也在内部检查这一点,以避免恢复和挂载查询之间的竞争条件。

Persisters

Persisters 接口

Persisters具有以下接口:

export interface Persister {
persistClient(persistClient: PersistedClient): Promisable<void>
restoreClient(): Promisable<PersistedClient | undefined>
removeClient(): Promisable<void>
}

PersistedClient 条目具有以下接口:

export interface PersistedClient {
timestamp: number
buster: string
cacheState: any
}

您可以导入这些接口(以构建persister):

import { PersistedClient, Persister } from "@tanstack/react-query-persist-client";

构建Persister

您可以按照自己的方式进行持久化。下面是构建Indexed DB persister的示例。与 Web Storage API相比,Indexed DB更快,存储容量超过5MB,并且不需要序列化。这意味着它可以直接存储JavaScript原生类型,例如DateFile

import { get, set, del } from "idb-keyval";
import { PersistedClient, Persister } from "@tanstack/react-query-persist-client";

/**
创建一个Indexed DB persister
@see <https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API>
*/
export function createIDBPersister(idbValidKey: IDBValidKey = "reactQuery") {
return {
persistClient: async (client: PersistedClient) => {
set(idbValidKey, client);
},
restoreClient: async () => {
return await get<PersistedClient>(idbValidKey);
},
removeClient: async () => {
await del(idbValidKey);
},
} as Persister;
}