v5, createPersister and IndexedDB: absolutely amazing! #6213
-
I'm using the latest v5 version: AMAZING!!!!!!! Thanks! I tried the I'm using it like this, what do you think? import {
experimental_createPersister,
type AsyncStorage,
} from "@tanstack/query-persist-client-core";
import { get, set, del, createStore, type UseStore } from "idb-keyval";
function newIdbStorage(idbStore: UseStore): AsyncStorage {
return {
getItem: async (key) => await get(key, idbStore),
setItem: async (key, value) => await set(key, value, idbStore),
removeItem: async (key) => await del(key, idbStore),
};
}
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 30, // 30 seconds
persister: !browser
? undefined
: experimental_createPersister({
storage: newIdbStorage(createStore("db_name", "store_name")),
maxAge: 1000 * 60 * 60 * 12, // 12 hours
}),
},
},
}); |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 20 replies
-
looks lovely |
Beta Was this translation helpful? Give feedback.
-
Hey! Thank you so much for the snippet. Works pretty great! One suggestion: The advantage of IndexedDB is that you can safely put objects into the storage without having to rely on serializing/deserializing the content like e.g. with LocalStorage. I have noticed that right now it would by default still stringify the content and then save it to IndexedDB. My suggestion would be to additionally add this into your persister: experimental_createPersister({
storage: newIdbStorage(createStore("db_name", "store_name")),
maxAge: 1000 * 60 * 60 * 12, // 12 hours,
// Just pass the data
serialize: (persistedQuery) => persistedQuery,
deserialize: (cached) => cached,
}) The only problem is that TypeScript will complain that this serialize/deserialize function is not assignable, because it expects a string as a return type and cached type. |
Beta Was this translation helpful? Give feedback.
-
With the newest version (v5.10), you can now add a type to the persister, so now we can combine my serializer solution with your IndexedDB solution :) import {
experimental_createPersister,
type AsyncStorage,
type PersistedQuery
} from "@tanstack/query-persist-client-core";
import { get, set, del, createStore, type UseStore } from "idb-keyval";
function newIdbStorage(idbStore: UseStore): AsyncStorage<PersistedQuery> {
return {
getItem: async (key) => await get(key, idbStore),
setItem: async (key, value) => await set(key, value, idbStore),
removeItem: async (key) => await del(key, idbStore),
};
}
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 30, // 30 seconds
persister: !browser
? undefined
: experimental_createPersister<PersistedQuery>({
storage: newIdbStorage(createStore("db_name", "store_name")),
maxAge: 1000 * 60 * 60 * 12, // 12 hours,
serialize: (persistedQuery) => persistedQuery,
deserialize: (cached) => cached,
}),
},
},
}); Under AsyncStorage and createrPersister, just add |
Beta Was this translation helpful? Give feedback.
-
When I use persistQueryClient, my data immediately appears upon reloading. However, when I switch to experimental_createPersister, my data is not there when reload. Could this mean I've set up something incorrectly? |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
@frederikhors @TkDodo @TheTimeWalker Thank you for the suggested solutions here! I have an additional question regarding this new import { createStore, del, get, set, UseStore, keys, getMany } from 'idb-keyval';
export async function restoreQueryClientCache() {
if (!idbStore) {
return;
}
const cachedKeys = await keys(idbStore);
const cachedValues = await getMany<PersistedQuery>(cachedKeys, idbStore);
for (const queryData of cachedValues) {
if (queryData?.buster !== UI_VERSION) {
continue;
}
if (!queryData?.state?.data) {
continue;
}
queryClient.setQueryData(queryData.queryKey, queryData.state.data, {
updatedAt: queryData.state.dataUpdatedAt,
});
}
}
restoreQueryClientCache().catch(console.error);
root.render(...); I am migrating from the solution which was suggested here. import { get, set, del } from 'idb-keyval'
import { PersistedClient, Persister } from '@tanstack/react-query-persist-client'
export function createIDBPersister(idbValidKey: IDBValidKey = 'reactQuery') {
return {
persistClient: async (client: PersistedClient) => { await set(idbValidKey, client) },
restoreClient: async () => { return await get<PersistedClient>(idbValidKey) },
removeClient: async () => { await del(idbValidKey) },
} as Persister
} With the previous solution, the query would initially resolve with the data from the cache (which was quite nice as if one reloads the page, they immediately see the previous data - no loading state). After migrating to the new Is a workaround to run Wondering if there would be an option to make the query client immediately restore some of the queries? |
Beta Was this translation helpful? Give feedback.
looks lovely