persistQueryClient
这是一组用于与"persisters"(用于将queryClient保存以供以后使用的工具)进行交互的实用程序。可以使用不同的persisters将客户端和缓存存储到许多不同的存储层中。
构建 Persisters
工作原理
重要提示 - 为了使 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 化并存储。
createSyncStoragePersister
和 createAsyncStoragePersister
以最多每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
用于persistQueryClientSave
和persistQueryClientSubscribe
(不要用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
- 可选的
- 在初始恢复完成时将被调用
- 可用于 resumePausedMutations
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原生类型,例如Date
和File
。
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;
}