forked from TanStack/query
/
index.ts
112 lines (102 loc) 路 2.68 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import type {
PersistedClient,
Persister,
PersistRetryer,
} from '@tanstack/query-persist-client-core'
interface Storage {
getItem: (key: string) => string | null
setItem: (key: string, value: string) => void
removeItem: (key: string) => void
}
interface CreateSyncStoragePersisterOptions {
/** The storage client used for setting and retrieving items from cache.
* For SSR pass in `undefined`.
*/
storage: Storage | undefined
/** The key to use when storing the cache */
key?: string
/** 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
retry?: PersistRetryer
}
export function createSyncStoragePersister({
storage,
key = `REACT_QUERY_OFFLINE_CACHE`,
throttleTime = 1000,
serialize = JSON.stringify,
deserialize = JSON.parse,
retry,
}: CreateSyncStoragePersisterOptions): Persister {
if (typeof storage !== 'undefined') {
const trySave = (persistedClient: PersistedClient): Error | undefined => {
try {
storage.setItem(key, serialize(persistedClient))
return
} catch (error) {
return error as Error
}
}
return {
persistClient: throttle((persistedClient) => {
let client: PersistedClient | undefined = persistedClient
let error = trySave(client)
let errorCount = 0
while (error && client) {
errorCount++
client = retry?.({
persistedClient: client,
error,
errorCount,
})
if (client) {
error = trySave(client)
}
}
}, throttleTime),
restoreClient: () => {
const cacheString = storage.getItem(key)
if (!cacheString) {
return
}
return deserialize(cacheString) as PersistedClient
},
removeClient: () => {
storage.removeItem(key)
},
}
}
return {
persistClient: noop,
restoreClient: () => undefined,
removeClient: noop,
}
}
function throttle<TArgs extends any[]>(
func: (...args: TArgs) => any,
wait = 100,
) {
let timer: ReturnType<typeof setTimeout> | null = null
let params: TArgs
return function (...args: TArgs) {
params = args
if (timer === null) {
timer = setTimeout(() => {
func(...params)
timer = null
}, wait)
}
}
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
function noop() {}