From db83b210c719f2785ad2e18e3b4500e55a8d4c44 Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Sun, 31 Oct 2021 16:26:39 +0200 Subject: [PATCH 1/3] feat: add optional functions to serialize and deserialize from Storage Persistors --- .../index.ts | 16 ++++++++++++++-- .../index.ts | 16 ++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/createAsyncStoragePersistor-experimental/index.ts b/src/createAsyncStoragePersistor-experimental/index.ts index 0141229bb5..daa5b673f9 100644 --- a/src/createAsyncStoragePersistor-experimental/index.ts +++ b/src/createAsyncStoragePersistor-experimental/index.ts @@ -14,16 +14,28 @@ interface CreateAsyncStoragePersistorOptions { /** To avoid spamming, * pass a time in ms to throttle saving the cache to disk */ throttleTime?: number + /** + * How to serialize the data to storage. + * @default `JSON.stringify` + */ + serialize?: (client: PersistedClient) => string + /** + * How to deserialize the data from storage. + * @default `JSON.parse` + */ + deserialize?: (cachedString: string) => PersistedClient } export const createAsyncStoragePersistor = ({ storage, key = `REACT_QUERY_OFFLINE_CACHE`, throttleTime = 1000, + serialize = JSON.stringify, + deserialize = JSON.parse, }: CreateAsyncStoragePersistorOptions): Persistor => { return { persistClient: asyncThrottle( - persistedClient => storage.setItem(key, JSON.stringify(persistedClient)), + persistedClient => storage.setItem(key, serialize(persistedClient)), { interval: throttleTime } ), restoreClient: async () => { @@ -33,7 +45,7 @@ export const createAsyncStoragePersistor = ({ return } - return JSON.parse(cacheString) as PersistedClient + return deserialize(cacheString) as PersistedClient }, removeClient: () => storage.removeItem(key), } diff --git a/src/createWebStoragePersistor-experimental/index.ts b/src/createWebStoragePersistor-experimental/index.ts index 3d54e64359..130f5d9f29 100644 --- a/src/createWebStoragePersistor-experimental/index.ts +++ b/src/createWebStoragePersistor-experimental/index.ts @@ -9,17 +9,29 @@ interface CreateWebStoragePersistorOptions { /** To avoid spamming, * pass a time in ms to throttle saving the cache to disk */ throttleTime?: number + /** + * How to serialize the data to storage. + * @default `JSON.stringify` + */ + serialize?: (client: PersistedClient) => string + /** + * How to deserialize the data from storage. + * @default `JSON.parse` + */ + deserialize?: (cachedString: string) => PersistedClient } export function createWebStoragePersistor({ storage, key = `REACT_QUERY_OFFLINE_CACHE`, throttleTime = 1000, + serialize = JSON.stringify, + deserialize = JSON.parse, }: CreateWebStoragePersistorOptions): Persistor { if (typeof storage !== 'undefined') { return { persistClient: throttle(persistedClient => { - storage.setItem(key, JSON.stringify(persistedClient)) + storage.setItem(key, serialize(persistedClient)) }, throttleTime), restoreClient: () => { const cacheString = storage.getItem(key) @@ -28,7 +40,7 @@ export function createWebStoragePersistor({ return } - return JSON.parse(cacheString) as PersistedClient + return deserialize(cacheString) as PersistedClient }, removeClient: () => { storage.removeItem(key) From 7b7391d94862367979076bba84aa2a6f57fda4a3 Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Sun, 31 Oct 2021 21:06:45 +0200 Subject: [PATCH 2/3] bugfix: make `asyncThrottle` more type-safe now infers the type of arguments of `func` correctly --- src/createAsyncStoragePersistor-experimental/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/createAsyncStoragePersistor-experimental/index.ts b/src/createAsyncStoragePersistor-experimental/index.ts index daa5b673f9..a9d43a3c76 100644 --- a/src/createAsyncStoragePersistor-experimental/index.ts +++ b/src/createAsyncStoragePersistor-experimental/index.ts @@ -51,16 +51,16 @@ export const createAsyncStoragePersistor = ({ } } -function asyncThrottle( - func: (...args: ReadonlyArray) => Promise, +function asyncThrottle( + func: (...args: Args) => Promise, { interval = 1000, limit = 1 }: { interval?: number; limit?: number } = {} ) { if (typeof func !== 'function') throw new Error('argument is not function.') const running = { current: false } let lastTime = 0 let timeout: number - const queue: Array = [] - return (...args: any) => + const queue: Array = [] + return (...args: Args) => (async () => { if (running.current) { lastTime = Date.now() From 439a744c0db5a863a6d8aa45ed2fa79ae7425de6 Mon Sep 17 00:00:00 2001 From: Ben Grynhaus Date: Sun, 31 Oct 2021 21:13:55 +0200 Subject: [PATCH 3/3] docs: update docs for `createAsyncStoragePersistor` and `createWebStoragePersistor` --- docs/src/pages/plugins/createAsyncStoragePersistor.md | 6 ++++++ docs/src/pages/plugins/createWebStoragePersistor.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/docs/src/pages/plugins/createAsyncStoragePersistor.md b/docs/src/pages/plugins/createAsyncStoragePersistor.md index 2d23b39f1b..6556c15999 100644 --- a/docs/src/pages/plugins/createAsyncStoragePersistor.md +++ b/docs/src/pages/plugins/createAsyncStoragePersistor.md @@ -60,6 +60,10 @@ interface CreateAsyncStoragePersistorOptions { /** To avoid localstorage spamming, * pass a time in ms to throttle saving the cache to disk */ throttleTime?: number + /** How to serialize the data to storage */ + serialize?: (client: PersistedClient) => string + /** How to deserialize the data from storage */ + deserialize?: (cachedString: string) => PersistedClient } interface AsyncStorage { @@ -75,5 +79,7 @@ The default options are: { key = `REACT_QUERY_OFFLINE_CACHE`, throttleTime = 1000, + serialize = JSON.stringify, + deserialize = JSON.parse, } ``` diff --git a/docs/src/pages/plugins/createWebStoragePersistor.md b/docs/src/pages/plugins/createWebStoragePersistor.md index 31c53061cf..983ac336bf 100644 --- a/docs/src/pages/plugins/createWebStoragePersistor.md +++ b/docs/src/pages/plugins/createWebStoragePersistor.md @@ -57,6 +57,10 @@ interface CreateWebStoragePersistorOptions { /** To avoid spamming, * pass a time in ms to throttle saving the cache to disk */ throttleTime?: number + /** How to serialize the data to storage */ + serialize?: (client: PersistedClient) => string + /** How to deserialize the data from storage */ + deserialize?: (cachedString: string) => PersistedClient } ``` @@ -66,5 +70,7 @@ The default options are: { key = `REACT_QUERY_OFFLINE_CACHE`, throttleTime = 1000, + serialize = JSON.stringify, + deserialize = JSON.parse, } ```