Skip to content

Commit e38342b

Browse files
committed
chore: some docs
1 parent cbd5df0 commit e38342b

File tree

2 files changed

+73
-5
lines changed

2 files changed

+73
-5
lines changed

docs/framework/react/plugins/createPersister.md

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ bun add @tanstack/query-persist-client-core
3535

3636
- Import the `experimental_createQueryPersister` function
3737
- Create a new `experimental_createQueryPersister`
38-
- you can pass any `storage` to it that adheres to the `AsyncStorage` or `Storage` interface - the example below uses the async-storage from React Native.
38+
- you can pass any `storage` to it that adheres to the `AsyncStorage` interface - the example below uses the async-storage from React Native.
3939
- Pass that `persister` as an option to your Query. This can be done either by passing it to the `defaultOptions` of the `QueryClient` or to any `useQuery` hook instance.
4040
- If you pass this `persister` as `defaultOptions`, all queries will be persisted to the provided `storage`. You can additionally narrow this down by passing `filters`. In contrast to the `persistClient` plugin, this will not persist the whole query client as a single item, but each query separately. As a key, the query hash is used.
4141
- If you provide this `persister` to a single `useQuery` hook, only this Query will be persisted.
@@ -69,6 +69,56 @@ const queryClient = new QueryClient({
6969

7070
The `createPersister` plugin technically wraps the `queryFn`, so it doesn't restore if the `queryFn` doesn't run. In that way, it acts as a caching layer between the Query and the network. Thus, the `networkMode` defaults to `'offlineFirst'` when a persister is used, so that restoring from the persistent storage can also happen even if there is no network connection.
7171

72+
## Additional utilities
73+
74+
Invoking `experimental_createQueryPersister` returns additional utilities in addition to `persisterFn` for easier implementation of userland functionalities.
75+
76+
### `persistQueryByKey(queryKey: QueryKey, queryClient: QueryClient): Promise<void>`
77+
78+
This function will persist `Query` to storage and key defined when creating persister.
79+
This utility might be used along `setQueryData` to persist optimistic update to storage without waiting for invalidation.
80+
81+
```tsx
82+
const persister = experimental_createQueryPersister({
83+
storage: AsyncStorage,
84+
maxAge: 1000 * 60 * 60 * 12, // 12 hours
85+
})
86+
87+
const queryClient = useQueryClient()
88+
89+
useMutation({
90+
mutationFn: updateTodo,
91+
onMutate: async (newTodo) => {
92+
...
93+
// Optimistically update to the new value
94+
queryClient.setQueryData(['todos'], (old) => [...old, newTodo])
95+
// And persist it to storage
96+
persister.persistQueryByKey(['todos'], queryClient)
97+
...
98+
},
99+
})
100+
```
101+
102+
### `retrieveQuery<T>(queryHash: string): Promise<T | undefined>`
103+
104+
This function would attempt to retrieve persisted query by `queryHash`.
105+
If `query` is `expired`, `busted` or `malformed` it would be removed from the storage instead, and `undefined` would be returned.
106+
107+
### `persisterGc(): Promise<void>`
108+
109+
This function can be used to sporadically clean up stoage from `expired`, `busted` or `malformed` entries.
110+
111+
For this function to work, your storage must expose `entries` method that would return a `key-value tuple array`.
112+
For example `Object.entries(localStorage)` for `localStorage` or `entries` from `idb-keyval`.
113+
114+
### `persisterRestoreAll(queryClient: QueryClient): Promise<void>`
115+
116+
This function can be used to restore all queries that are currently stored by persister in one go.
117+
For example when your app is starting up in offline mode, or you want data from previous session to be immediately available without intermediate `loading` state.
118+
119+
For this function to work, your storage must expose `entries` method that would return a `key-value tuple array`.
120+
For example `Object.entries(localStorage)` for `localStorage` or `entries` from `idb-keyval`.
121+
72122
## API
73123

74124
### `experimental_createQueryPersister`
@@ -118,10 +168,11 @@ export interface StoragePersisterOptions {
118168
filters?: QueryFilters
119169
}
120170

121-
interface AsyncStorage {
122-
getItem: (key: string) => Promise<string | undefined | null>
123-
setItem: (key: string, value: string) => Promise<unknown>
124-
removeItem: (key: string) => Promise<void>
171+
interface AsyncStorage<TStorageValue = string> {
172+
getItem: (key: string) => MaybePromise<TStorageValue | undefined | null>
173+
setItem: (key: string, value: TStorageValue) => MaybePromise<unknown>
174+
removeItem: (key: string) => MaybePromise<void>
175+
entries?: () => MaybePromise<Array<[key: string, value: TStorageValue]>>
125176
}
126177
```
127178

packages/query-persist-client-core/src/createPersister.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,22 @@ export function experimental_createQueryPersister<TStorageValue = string>({
145145
return
146146
}
147147

148+
async function persistQueryByKey(queryKey: QueryKey, queryClient: QueryClient) {
149+
if (storage != null) {
150+
const query = queryClient.getQueryCache().find({ queryKey })
151+
if (query) {
152+
persistQuery(query)
153+
} else {
154+
if (process.env.NODE_ENV === 'development') {
155+
console.warn(
156+
'Could not find query to be persisted. QueryKey:',
157+
JSON.stringify(queryKey)
158+
)
159+
}
160+
}
161+
}
162+
}
163+
148164
async function persistQuery(query: Query) {
149165
if (storage != null) {
150166
const storageKey = `${prefix}-${query.queryHash}`
@@ -251,6 +267,7 @@ export function experimental_createQueryPersister<TStorageValue = string>({
251267
return {
252268
persisterFn,
253269
persistQuery,
270+
persistQueryByKey,
254271
retrieveQuery,
255272
persisterGc,
256273
persisterRestoreAll,

0 commit comments

Comments
 (0)