@shihengtech/utils 0.0.7 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sh-utils.js +46 -2
- package/dist/sh-utils.js.map +1 -1
- package/es/index.js +152 -27
- package/es/index.js.map +1 -1
- package/lib/index.d.ts +86 -6
- package/lib/index.js +155 -26
- package/lib/index.js.map +1 -1
- package/package.json +14 -12
package/es/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { useRef, useEffect, useState } from 'react';
|
|
1
2
|
import localforage from 'localforage';
|
|
2
3
|
import { equals } from 'ramda';
|
|
3
4
|
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
6
|
+
var __defProps = Object.defineProperties;
|
|
7
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
8
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
9
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
10
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -17,6 +20,19 @@ var __spreadValues = (a, b) => {
|
|
|
17
20
|
}
|
|
18
21
|
return a;
|
|
19
22
|
};
|
|
23
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
24
|
+
var __objRest = (source, exclude) => {
|
|
25
|
+
var target = {};
|
|
26
|
+
for (var prop in source)
|
|
27
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
28
|
+
target[prop] = source[prop];
|
|
29
|
+
if (source != null && __getOwnPropSymbols)
|
|
30
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
31
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
32
|
+
target[prop] = source[prop];
|
|
33
|
+
}
|
|
34
|
+
return target;
|
|
35
|
+
};
|
|
20
36
|
var __async = (__this, __arguments, generator) => {
|
|
21
37
|
return new Promise((resolve, reject) => {
|
|
22
38
|
var fulfilled = (value) => {
|
|
@@ -61,6 +77,18 @@ var ReplaySubject = class {
|
|
|
61
77
|
}
|
|
62
78
|
}
|
|
63
79
|
};
|
|
80
|
+
function useLaziedRef(value) {
|
|
81
|
+
const ref = useRef();
|
|
82
|
+
if (ref.current == null) {
|
|
83
|
+
ref.current = value();
|
|
84
|
+
}
|
|
85
|
+
return ref;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/hooks/useLaziedConst/index.ts
|
|
89
|
+
function useLaziedConst(value) {
|
|
90
|
+
return useLaziedRef(value).current;
|
|
91
|
+
}
|
|
64
92
|
|
|
65
93
|
// src/utils/fnRunner/index.ts
|
|
66
94
|
function fnRunner(fn, retryTimes = 0) {
|
|
@@ -103,43 +131,45 @@ function createQueryWithCache(key, fn, options) {
|
|
|
103
131
|
} = __spreadValues({
|
|
104
132
|
deps: [],
|
|
105
133
|
retry: 0,
|
|
106
|
-
equals:
|
|
134
|
+
equals: equals,
|
|
107
135
|
compareBeforeUpdate: equals,
|
|
108
136
|
remoteMemoryCache: false
|
|
109
137
|
}, options);
|
|
138
|
+
let fnRunCount = 0;
|
|
110
139
|
const cacheUpdateSubject = new ReplaySubject(1);
|
|
111
140
|
const resolveDeps = () => typeof deps === "function" ? deps() : deps;
|
|
112
|
-
const queryFnEnhancer = (fn2, options2) => ((args) => {
|
|
113
|
-
const promiseResult = fn2(args);
|
|
141
|
+
const queryFnEnhancer = (fn2, options2) => ((args, rest) => {
|
|
142
|
+
const promiseResult = fn2(args, rest);
|
|
114
143
|
promiseResult.then((result) => {
|
|
115
144
|
var _a;
|
|
116
145
|
const res = { type: options2.type, result };
|
|
117
|
-
(_a = options2.onSuccess) == null ? void 0 : _a.call(options2, res);
|
|
146
|
+
rest.runCount === fnRunCount && ((_a = options2.onSuccess) == null ? void 0 : _a.call(options2, res));
|
|
118
147
|
return res;
|
|
119
|
-
},
|
|
148
|
+
}, (error) => {
|
|
149
|
+
var _a;
|
|
150
|
+
rest.runCount === fnRunCount && ((_a = options2.onError) == null ? void 0 : _a.call(options2, error));
|
|
151
|
+
}).catch(() => {
|
|
120
152
|
});
|
|
121
153
|
return promiseResult;
|
|
122
154
|
});
|
|
123
|
-
const getLocalCache = (
|
|
155
|
+
const getLocalCache = (_0, _1) => __async(null, [_0, _1], function* (_args, { deps: deps2 }) {
|
|
124
156
|
const cache = yield db.getItem(key);
|
|
125
|
-
if (cache && (!version || cache.version === version) && (!cache.expires || cache.expires > Date.now()) && equals$1(cache.deps,
|
|
157
|
+
if (cache && (!version || cache.version === version) && (!cache.expires || cache.expires > Date.now()) && equals$1(cache.deps, deps2)) {
|
|
126
158
|
return cache.result;
|
|
127
159
|
}
|
|
128
160
|
throw new Error("Cache not found");
|
|
129
161
|
});
|
|
130
162
|
const remoteResultCache = {
|
|
131
163
|
success: false,
|
|
132
|
-
args: [],
|
|
133
164
|
deps: [],
|
|
134
165
|
result: null
|
|
135
166
|
};
|
|
136
167
|
const clearMemoryCache = () => {
|
|
137
168
|
remoteResultCache.success = false;
|
|
138
169
|
remoteResultCache.result = null;
|
|
139
|
-
remoteResultCache.args = [];
|
|
140
170
|
remoteResultCache.deps = [];
|
|
141
171
|
};
|
|
142
|
-
const queryWithMemoryCache = (args) => {
|
|
172
|
+
const queryWithMemoryCache = (args, deps2) => {
|
|
143
173
|
if (!remoteMemoryCache) {
|
|
144
174
|
return {
|
|
145
175
|
type: "remote",
|
|
@@ -149,15 +179,13 @@ function createQueryWithCache(key, fn, options) {
|
|
|
149
179
|
)
|
|
150
180
|
};
|
|
151
181
|
}
|
|
152
|
-
|
|
153
|
-
if (remoteResultCache.success && equals$1(remoteResultCache.args, args) && equals$1(remoteResultCache.deps, currentDeps)) {
|
|
182
|
+
if (remoteResultCache.success && equals$1(remoteResultCache.deps, deps2)) {
|
|
154
183
|
return {
|
|
155
184
|
type: "memory",
|
|
156
185
|
promiseResult: remoteResultCache.result
|
|
157
186
|
};
|
|
158
187
|
}
|
|
159
|
-
remoteResultCache.
|
|
160
|
-
remoteResultCache.deps = currentDeps;
|
|
188
|
+
remoteResultCache.deps = deps2;
|
|
161
189
|
remoteResultCache.success = true;
|
|
162
190
|
const result = remoteResultCache.result = fnRunner(
|
|
163
191
|
() => fn(...args),
|
|
@@ -166,18 +194,19 @@ function createQueryWithCache(key, fn, options) {
|
|
|
166
194
|
Promise.resolve(result).catch(clearMemoryCache);
|
|
167
195
|
return { type: "remote", promiseResult: result };
|
|
168
196
|
};
|
|
169
|
-
const
|
|
197
|
+
const queryRemote = (args, queryOption) => __async(null, null, function* () {
|
|
170
198
|
const rs = {
|
|
171
199
|
type: "remote",
|
|
172
200
|
result: null
|
|
173
201
|
};
|
|
202
|
+
const { runCount, deps: deps2 } = queryOption;
|
|
174
203
|
try {
|
|
175
|
-
const { type, promiseResult } = queryWithMemoryCache(args);
|
|
204
|
+
const { type, promiseResult } = queryWithMemoryCache(args, deps2);
|
|
176
205
|
const result = rs.result = yield promiseResult;
|
|
177
|
-
type === "remote" && (!cacheEnabled || (yield cacheEnabled(
|
|
178
|
-
const oldCache = yield getLocalCache(args).catch(() => null);
|
|
206
|
+
runCount === fnRunCount && type === "remote" && (!cacheEnabled || (yield cacheEnabled(deps2))) && Promise.resolve().then(() => __async(null, null, function* () {
|
|
207
|
+
const oldCache = yield getLocalCache(args, queryOption).catch(() => null);
|
|
179
208
|
const cacheData = __spreadValues(__spreadValues({
|
|
180
|
-
deps:
|
|
209
|
+
deps: deps2,
|
|
181
210
|
result
|
|
182
211
|
}, version && { version }), maxAge && { expires: Date.now() + maxAge });
|
|
183
212
|
db.setItem(key, cacheData);
|
|
@@ -198,25 +227,38 @@ function createQueryWithCache(key, fn, options) {
|
|
|
198
227
|
}
|
|
199
228
|
}
|
|
200
229
|
return rs.result;
|
|
201
|
-
})
|
|
230
|
+
});
|
|
202
231
|
const _fn = (...args) => __async(null, null, function* () {
|
|
203
232
|
yield beforeRequest == null ? void 0 : beforeRequest();
|
|
233
|
+
const runCount = ++fnRunCount;
|
|
234
|
+
const currentDeps = args.concat(resolveDeps());
|
|
235
|
+
const queryOption = { runCount, deps: currentDeps };
|
|
236
|
+
const isCacheDisabled = cacheEnabled && !(yield cacheEnabled(currentDeps));
|
|
204
237
|
const [cacheResult, remoteResult] = [
|
|
205
|
-
queryFnEnhancer(getLocalCache, { type: "local", onSuccess })(args),
|
|
206
|
-
|
|
238
|
+
isCacheDisabled ? null : queryFnEnhancer(getLocalCache, { type: "local", onSuccess })(args, queryOption),
|
|
239
|
+
queryFnEnhancer(queryRemote, { type: "remote", onSuccess, onError })(args, queryOption)
|
|
207
240
|
];
|
|
208
|
-
const result = yield Promise.race([
|
|
241
|
+
const result = cacheResult ? yield Promise.race([
|
|
209
242
|
cacheResult.catch(() => remoteResult),
|
|
210
243
|
remoteResult
|
|
211
|
-
]);
|
|
244
|
+
]) : remoteResult;
|
|
212
245
|
return result;
|
|
213
246
|
});
|
|
214
|
-
_fn.refresh = (...args) =>
|
|
247
|
+
_fn.refresh = (...args) => __async(null, null, function* () {
|
|
248
|
+
yield beforeRequest == null ? void 0 : beforeRequest();
|
|
249
|
+
const runCount = ++fnRunCount;
|
|
250
|
+
const currentDeps = args.concat(resolveDeps());
|
|
251
|
+
const queryOption = { runCount, deps: currentDeps };
|
|
252
|
+
return queryFnEnhancer(
|
|
253
|
+
queryRemote,
|
|
254
|
+
{ type: "remote", onSuccess, onError }
|
|
255
|
+
)(args, queryOption);
|
|
256
|
+
});
|
|
215
257
|
_fn.getCache = () => db.getItem(key);
|
|
216
258
|
_fn.updateCache = (value) => __async(null, null, function* () {
|
|
217
259
|
if (typeof value === "function") {
|
|
218
260
|
const prevCache = yield _fn.getCache().catch(() => null);
|
|
219
|
-
const newCache = value(prevCache);
|
|
261
|
+
const newCache = yield value(prevCache);
|
|
220
262
|
yield db.setItem(key, newCache);
|
|
221
263
|
} else {
|
|
222
264
|
yield db.setItem(key, value);
|
|
@@ -240,6 +282,89 @@ createQueryWithCache.useDb = (newDb) => {
|
|
|
240
282
|
}
|
|
241
283
|
};
|
|
242
284
|
|
|
243
|
-
|
|
285
|
+
// src/hooks/useQueryWithCache/index.ts
|
|
286
|
+
var FETCHING_STATUS = /* @__PURE__ */ ((FETCHING_STATUS2) => {
|
|
287
|
+
FETCHING_STATUS2[FETCHING_STATUS2["IDLE"] = 2] = "IDLE";
|
|
288
|
+
FETCHING_STATUS2[FETCHING_STATUS2["PENDING"] = 4] = "PENDING";
|
|
289
|
+
FETCHING_STATUS2[FETCHING_STATUS2["INITIALIZING"] = 5] = "INITIALIZING";
|
|
290
|
+
FETCHING_STATUS2[FETCHING_STATUS2["SUCCESS"] = 8] = "SUCCESS";
|
|
291
|
+
FETCHING_STATUS2[FETCHING_STATUS2["LOCAL_SUCCESS"] = 9] = "LOCAL_SUCCESS";
|
|
292
|
+
FETCHING_STATUS2[FETCHING_STATUS2["ERROR"] = 16] = "ERROR";
|
|
293
|
+
return FETCHING_STATUS2;
|
|
294
|
+
})(FETCHING_STATUS || {});
|
|
295
|
+
function useQueryWithCache(key, fn, deps = [], options) {
|
|
296
|
+
const _a = options || {}, {
|
|
297
|
+
enabled = true,
|
|
298
|
+
initialData,
|
|
299
|
+
onSuccess,
|
|
300
|
+
onError,
|
|
301
|
+
onFinished,
|
|
302
|
+
useCustomEffect = useEffect
|
|
303
|
+
} = _a, restOptions = __objRest(_a, [
|
|
304
|
+
"enabled",
|
|
305
|
+
"initialData",
|
|
306
|
+
"onSuccess",
|
|
307
|
+
"onError",
|
|
308
|
+
"onFinished",
|
|
309
|
+
"useCustomEffect"
|
|
310
|
+
]);
|
|
311
|
+
const [status, setStatus] = useState(2 /* IDLE */);
|
|
312
|
+
const [state, setState] = useState(() => ({
|
|
313
|
+
source: "local",
|
|
314
|
+
data: typeof initialData === "function" ? initialData() : initialData,
|
|
315
|
+
error: null
|
|
316
|
+
}));
|
|
317
|
+
const infoRef = useRef({ deps, fn, onSuccess, onError, onFinished });
|
|
318
|
+
infoRef.current.deps = deps;
|
|
319
|
+
infoRef.current.fn = fn;
|
|
320
|
+
infoRef.current.onSuccess = onSuccess;
|
|
321
|
+
infoRef.current.onError = onError;
|
|
322
|
+
infoRef.current.onFinished = onFinished;
|
|
323
|
+
const cachedFn = useLaziedConst(() => createQueryWithCache(key, () => infoRef.current.fn(), __spreadProps(__spreadValues({}, restOptions), {
|
|
324
|
+
deps: () => infoRef.current.deps,
|
|
325
|
+
beforeRequest: () => {
|
|
326
|
+
setStatus((s) => s === 2 /* IDLE */ ? 5 /* INITIALIZING */ : 4 /* PENDING */);
|
|
327
|
+
},
|
|
328
|
+
onSuccess: (result) => {
|
|
329
|
+
var _a2, _b, _c, _d;
|
|
330
|
+
setStatus(result.type === "local" ? 9 /* LOCAL_SUCCESS */ : 8 /* SUCCESS */);
|
|
331
|
+
setState((s) => __spreadProps(__spreadValues({}, s), {
|
|
332
|
+
source: result.type,
|
|
333
|
+
data: result.result,
|
|
334
|
+
error: null,
|
|
335
|
+
dataUpdatedAt: Date.now()
|
|
336
|
+
}));
|
|
337
|
+
(_b = (_a2 = infoRef.current).onSuccess) == null ? void 0 : _b.call(_a2, result.result);
|
|
338
|
+
(_d = (_c = infoRef.current).onFinished) == null ? void 0 : _d.call(_c, { success: true, data: result.result });
|
|
339
|
+
},
|
|
340
|
+
onError: (error) => {
|
|
341
|
+
var _a2, _b, _c, _d;
|
|
342
|
+
setStatus(16 /* ERROR */);
|
|
343
|
+
setState((s) => __spreadProps(__spreadValues({}, s), {
|
|
344
|
+
error,
|
|
345
|
+
errorUpdatedAt: Date.now()
|
|
346
|
+
}));
|
|
347
|
+
(_b = (_a2 = infoRef.current).onError) == null ? void 0 : _b.call(_a2, error);
|
|
348
|
+
(_d = (_c = infoRef.current).onFinished) == null ? void 0 : _d.call(_c, { success: false, error });
|
|
349
|
+
}
|
|
350
|
+
})));
|
|
351
|
+
useCustomEffect(() => {
|
|
352
|
+
if (!enabled)
|
|
353
|
+
return;
|
|
354
|
+
cachedFn();
|
|
355
|
+
}, [enabled, ...deps]);
|
|
356
|
+
return __spreadProps(__spreadValues({}, state), {
|
|
357
|
+
initializing: status === 5 /* INITIALIZING */,
|
|
358
|
+
loading: !!(status & 4 /* PENDING */),
|
|
359
|
+
isSuccess: !!(status & 8 /* SUCCESS */),
|
|
360
|
+
isError: status === 16 /* ERROR */,
|
|
361
|
+
setState,
|
|
362
|
+
run: cachedFn,
|
|
363
|
+
refresh: cachedFn.refresh,
|
|
364
|
+
clearCache: cachedFn.clearCache
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { FETCHING_STATUS, ReplaySubject, createQueryWithCache, fnRunner, useLaziedConst, useLaziedRef, useQueryWithCache };
|
|
244
369
|
//# sourceMappingURL=index.js.map
|
|
245
370
|
//# sourceMappingURL=index.js.map
|
package/es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/class/ReplaySubject/index.ts","../src/utils/fnRunner/index.ts","../src/utils/createQueryWithCache/index.ts"],"names":["equals","deepEquals","fn","options"],"mappings":"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","file":"index.js","sourcesContent":["class ReplaySubject<T> {\n private maxBufferSize: number\n private buffer: T[] = []\n\n private subscriptions: ((data: T) => void)[] = []\n\n constructor(maxBufferSize = 1) {\n this.maxBufferSize = maxBufferSize\n }\n\n subscribe(fn: (data: T) => void) {\n this.subscriptions.push(fn)\n this.buffer.forEach(data => fn(data))\n return () => this.unsubscribe(fn)\n }\n\n unsubscribe(fn: (data: T) => void) {\n this.subscriptions = this.subscriptions.filter(f => f !== fn)\n }\n\n next(data: T) {\n this.subscriptions.forEach(fn => fn(data))\n this.buffer.push(data)\n if (this.buffer.length > this.maxBufferSize) {\n this.buffer = this.buffer.slice(1)\n }\n }\n}\n\nexport { ReplaySubject }\n","export async function fnRunner<T extends (...args: any[]) => Promise<any>>(fn: T, retryTimes: number = 0): Promise<Awaited<ReturnType<T>>> {\n const times = (retryTimes || 0) + 1\n for (let i = 0; i < times; i++) {\n try {\n return await fn()\n }\n catch (error) {\n // Only throw if this was the last attempt\n if (i === times - 1) {\n throw error\n }\n }\n }\n // This line should never be reached, but it's required for type safety.\n throw new Error('fnRunner: Unexpected error - all retries exhausted.')\n}\n","import localforage from 'localforage'\nimport { equals as deepEquals } from 'ramda'\nimport { ReplaySubject } from '../../class'\nimport { fnRunner } from '../fnRunner'\n\ntype DBType = Pick<\n LocalForage,\n 'getItem' | 'setItem' | 'removeItem' | 'clear'\n // 这些可以暂时不考虑\n // | 'clear' | 'keys' | 'length'\n>\n\nconst DB_NAME = 'sh-cache-common'\n\nlet db: DBType = localforage.createInstance({\n name: DB_NAME,\n storeName: 'main-store',\n // driver: [localforage.LOCALSTORAGE, localforage.INDEXEDDB, localforage.WEBSQL],\n})\n\ninterface CacheItem<T extends (...args: any[]) => Promise<any>> {\n /** 缓存参数 */\n deps: any[]\n /** 缓存版本,用于缓存数据结构变更 */\n version?: string\n /** 缓存过期时间,为空表示永不过期 */\n expires?: number\n /** 缓存结果 */\n result: Awaited<ReturnType<T>>\n}\n\ninterface CacheOptions<T extends (...args: any[]) => Promise<any>> {\n /** 缓存过期时间,为空表示永不过期 */\n maxAge?: number\n /** 缓存版本,用于缓存数据结构变更 */\n version?: string\n /** 依赖项,用于缓存依赖项变更。支持函数形式,函数会在运行时调用取值 */\n deps?: readonly unknown[] | (() => readonly unknown[])\n /**\n * 重试次数,为0表示不重试\n * @default 0\n */\n retry?: number\n /**\n * 是否比较旧缓存与新缓存后再触发 onCacheUpdate\n * 为 true 时,只有当新旧缓存不一致时才触发 onCacheUpdate\n * 为 false 时,总是触发 onCacheUpdate\n * @default R.equals\n */\n compareBeforeUpdate?:\n | ((prev: Awaited<ReturnType<T>>, next: Awaited<ReturnType<T>>) => boolean)\n | false\n /**\n * 是否启用远程内存缓存\n * 为 true 时,启用远程内存缓存\n * 为 false 时,不启用远程内存缓存\n * @default false\n */\n remoteMemoryCache?: boolean\n /**\n * 比较依赖项(函数参数及 deps)是否相等\n * @default (a, b) => a.length === b.length && a.every((item, index) => item === b[index])\n */\n equals?: (prev: readonly unknown[], next: readonly unknown[]) => boolean\n /**\n * 根据入参决定是否添加缓存\n * 不传的话默认启用缓存\n */\n cacheEnabled?: (args: Parameters<T>) => Promise<boolean>\n /** 请求前回调 */\n beforeRequest?: () => Promise<void> | void\n /** 请求成功回调 */\n onSuccess?: (result: {\n type: 'local' | 'remote'\n result: Awaited<ReturnType<T>>\n }) => void\n /** 请求错误回调 */\n onError?: (error: any) => void\n /** 远程请求错误处理 */\n errorHandler?: (error: any) => any\n // /** 缓存更新回调 */\n // onCacheUpdate?: (\n // result: Awaited<ReturnType<T>>,\n // cacheData: CacheItem<T>,\n // ) => void;\n}\n\ninterface CacheUpdateEvent<T extends (...args: any[]) => Promise<any>> {\n result: Awaited<ReturnType<T>>\n cacheData: CacheItem<T>\n isCacheHit: boolean\n}\n\nfunction createQueryWithCache<T extends (...args: any[]) => Promise<any>>(key: string, fn: T, options?: CacheOptions<T>) {\n const {\n deps,\n retry,\n maxAge,\n version,\n compareBeforeUpdate,\n remoteMemoryCache,\n equals,\n cacheEnabled,\n beforeRequest,\n onSuccess,\n onError,\n errorHandler,\n } = {\n deps: [],\n retry: 0,\n equals: (a, b) =>\n a.length === b.length && a.every((item, index) => item === b[index]),\n compareBeforeUpdate: deepEquals,\n remoteMemoryCache: false,\n ...options,\n } satisfies CacheOptions<T>\n\n const cacheUpdateSubject = new ReplaySubject<CacheUpdateEvent<T>>(1)\n\n /** 解析 deps,如果元素是函数则调用获取值 */\n const resolveDeps = () => (typeof deps === 'function' ? deps() : deps)\n\n const queryFnEnhancer = (fn: (args: Parameters<T>) => Promise<ReturnType<T>>, options: Pick<CacheOptions<T>, 'onSuccess' | 'onError'> & { type: 'remote' | 'local' }) => (((args) => {\n const promiseResult = fn(args)\n\n promiseResult\n .then((result) => {\n const res = { type: options.type, result: result as Awaited<ReturnType<T>> }\n options.onSuccess?.(res)\n return res\n }, options.onError)\n .catch(() => {})\n\n return promiseResult\n }) as typeof fn)\n\n const getLocalCache = async (args: Parameters<T>) => {\n const cache = await db.getItem<CacheItem<T>>(key)\n if (\n cache\n && (!version || cache.version === version)\n && (!cache.expires || cache.expires > Date.now())\n && equals(cache.deps, args.concat(resolveDeps()))\n ) {\n return cache.result\n }\n\n throw new Error('Cache not found')\n }\n\n const remoteResultCache: {\n success: boolean\n args: Parameters<T>\n deps: readonly unknown[]\n result: ReturnType<T> | null\n } = {\n success: false,\n args: [] as any,\n deps: [],\n result: null,\n }\n\n const clearMemoryCache = () => {\n remoteResultCache.success = false\n remoteResultCache.result = null\n remoteResultCache.args = [] as any\n remoteResultCache.deps = []\n }\n\n const queryWithMemoryCache = (args: Parameters<T>) => {\n if (!remoteMemoryCache) {\n return {\n type: 'remote' as const,\n promiseResult: fnRunner(\n () => fn(...args),\n retry,\n ),\n }\n }\n\n const currentDeps = resolveDeps()\n if (\n remoteResultCache.success\n && equals(remoteResultCache.args, args)\n && equals(remoteResultCache.deps, currentDeps)\n ) {\n return {\n type: 'memory' as const,\n promiseResult: remoteResultCache.result!,\n }\n }\n\n remoteResultCache.args = args\n remoteResultCache.deps = currentDeps\n remoteResultCache.success = true\n const result = (remoteResultCache.result = fnRunner(\n () => fn(...args),\n retry,\n ) as ReturnType<T>)\n\n Promise.resolve(result)\n .catch(clearMemoryCache)\n\n return { type: 'remote' as const, promiseResult: result }\n }\n\n const queryRemoteWithEnhancer = queryFnEnhancer(async (args: Parameters<T>) => {\n const rs = {\n type: 'remote' as const,\n result: null as unknown as Awaited<ReturnType<T>>,\n }\n\n try {\n const { type, promiseResult } = queryWithMemoryCache(args)\n const result = (rs.result = await promiseResult)\n\n // 设置缓存\n type === 'remote'\n && (!cacheEnabled || (await cacheEnabled(args)))\n && Promise.resolve().then(async () => {\n const oldCache = await getLocalCache(args).catch(() => null)\n\n const cacheData: CacheItem<T> = {\n deps: args.concat(resolveDeps()),\n result,\n ...(version && { version }),\n ...(maxAge && { expires: Date.now() + maxAge }),\n }\n db.setItem(key, cacheData)\n\n // 如果配置了比较,且旧缓存存在且与新结果相等,则不触发 onCacheUpdate\n if (\n compareBeforeUpdate\n && oldCache\n && compareBeforeUpdate(oldCache, result)\n ) {\n return\n }\n cacheUpdateSubject.next({\n result,\n cacheData,\n isCacheHit: !!oldCache,\n })\n })\n }\n catch (error) {\n if (errorHandler) {\n rs.result = (await errorHandler(error)) as Awaited<ReturnType<T>>\n }\n else {\n throw error\n }\n }\n\n return rs.result\n }, { type: 'remote' as const, onSuccess, onError })\n\n const _fn = async (...args: Parameters<T>) => {\n await beforeRequest?.()\n\n const [cacheResult, remoteResult] = [\n queryFnEnhancer(getLocalCache, { type: 'local' as const, onSuccess })(args),\n queryRemoteWithEnhancer(args),\n ]\n const result = await Promise.race([\n cacheResult.catch(() => remoteResult),\n remoteResult,\n ])\n\n return result\n }\n\n _fn.refresh = (...args: Parameters<T>) => queryRemoteWithEnhancer(args)\n\n _fn.getCache = () => db.getItem<CacheItem<T>>(key)\n\n _fn.updateCache = async (value: (CacheItem<T> | ((prev: CacheItem<T> | null) => CacheItem<T>))) => {\n if (typeof value === 'function') {\n const prevCache = await _fn.getCache().catch(() => null)\n const newCache = value(prevCache)\n await db.setItem(key, newCache)\n }\n else {\n await db.setItem(key, value)\n }\n }\n\n _fn.subscribeCacheUpdate = (fn: (data: CacheUpdateEvent<T>) => void) =>\n cacheUpdateSubject.subscribe(fn)\n\n _fn.clearCache = async () => {\n clearMemoryCache()\n await db.removeItem(key)\n }\n\n return _fn\n}\n\n/**\n * 使用自定义数据库实例\n * @param newDb 数据库实例或 storeName,如果为字符串,则使用 localforage 创建一个实例\n */\ncreateQueryWithCache.useDb = <T extends string>(newDb: DBType | (T extends 'main-store' ? never : T)) => {\n if (typeof newDb === 'string') {\n db = localforage.createInstance({\n name: DB_NAME,\n storeName: newDb,\n })\n }\n else {\n db = newDb\n }\n}\n\nexport { createQueryWithCache }\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/class/ReplaySubject/index.ts","../src/hooks/useLaziedRef/index.ts","../src/hooks/useLaziedConst/index.ts","../src/utils/fnRunner/index.ts","../src/utils/createQueryWithCache/index.ts","../src/hooks/useQueryWithCache/index.ts"],"names":["equals","deepEquals","fn","options","deps","FETCHING_STATUS","useRef","_a"],"mappings":"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","file":"index.js","sourcesContent":["class ReplaySubject<T> {\n private maxBufferSize: number\n private buffer: T[] = []\n\n private subscriptions: ((data: T) => void)[] = []\n\n constructor(maxBufferSize = 1) {\n this.maxBufferSize = maxBufferSize\n }\n\n subscribe(fn: (data: T) => void) {\n this.subscriptions.push(fn)\n this.buffer.forEach(data => fn(data))\n return () => this.unsubscribe(fn)\n }\n\n unsubscribe(fn: (data: T) => void) {\n this.subscriptions = this.subscriptions.filter(f => f !== fn)\n }\n\n next(data: T) {\n this.subscriptions.forEach(fn => fn(data))\n this.buffer.push(data)\n if (this.buffer.length > this.maxBufferSize) {\n this.buffer = this.buffer.slice(1)\n }\n }\n}\n\nexport { ReplaySubject }\n","import { useRef } from 'react'\n\nexport function useLaziedRef<T extends NonNullable<unknown>>(value: () => T) {\n const ref = useRef<T>()\n\n if (ref.current == null) {\n ref.current = value()\n }\n\n return ref as React.MutableRefObject<T>\n}\n","import { useLaziedRef } from '../useLaziedRef'\n\nexport function useLaziedConst<T extends NonNullable<unknown>>(value: () => T) {\n return useLaziedRef(value).current\n}\n","export async function fnRunner<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n retryTimes: number = 0,\n): Promise<Awaited<ReturnType<T>>> {\n const times = (retryTimes || 0) + 1\n for (let i = 0; i < times; i++) {\n try {\n return await fn()\n }\n catch (error) {\n // Only throw if this was the last attempt\n if (i === times - 1) {\n throw error\n }\n }\n }\n // This line should never be reached, but it's required for type safety.\n throw new Error('fnRunner: Unexpected error - all retries exhausted.')\n}\n","import localforage from 'localforage'\nimport { equals as deepEquals } from 'ramda'\nimport { ReplaySubject } from '../../class'\nimport { fnRunner } from '../fnRunner'\n\ntype DBType = Pick<\n LocalForage,\n 'getItem' | 'setItem' | 'removeItem' | 'clear'\n // 这些可以暂时不考虑\n // | 'clear' | 'keys' | 'length'\n>\n\nconst DB_NAME = 'sh-cache-common'\n\nlet db: DBType = localforage.createInstance({\n name: DB_NAME,\n storeName: 'main-store',\n // driver: [localforage.LOCALSTORAGE, localforage.INDEXEDDB, localforage.WEBSQL],\n})\n\ninterface CacheItem<T extends (...args: any[]) => Promise<any>> {\n /** 缓存参数 */\n deps: any[]\n /** 缓存版本,用于缓存数据结构变更 */\n version?: string\n /** 缓存过期时间,为空表示永不过期 */\n expires?: number\n /** 缓存结果 */\n result: Awaited<ReturnType<T>>\n}\n\ninterface CacheOptions<T extends (...args: any[]) => Promise<any>> {\n /** 缓存过期时间,为空表示永不过期 */\n maxAge?: number\n /** 缓存版本,用于缓存数据结构变更 */\n version?: string\n /** 依赖项,用于缓存依赖项变更。支持函数形式,函数会在运行时调用取值 */\n deps?: readonly unknown[] | (() => readonly unknown[])\n /**\n * 重试次数,为0表示不重试\n * @default 0\n */\n retry?: number\n /**\n * 是否比较旧缓存与新缓存后再触发 onCacheUpdate\n * 为 true 时,只有当新旧缓存不一致时才触发 onCacheUpdate\n * 为 false 时,总是触发 onCacheUpdate\n * @default R.equals\n */\n compareBeforeUpdate?:\n | ((prev: Awaited<ReturnType<T>>, next: Awaited<ReturnType<T>>) => boolean)\n | false\n /**\n * 是否启用远程内存缓存\n * 为 true 时,启用远程内存缓存\n * 为 false 时,不启用远程内存缓存\n * @default false\n */\n remoteMemoryCache?: boolean\n /**\n * 比较依赖项(函数参数及 deps)是否相等\n * @default R.equals\n */\n equals?: (prev: readonly unknown[], next: readonly unknown[]) => boolean\n /**\n * 根据入参决定是否启用缓存\n */\n cacheEnabled?: (deps: readonly unknown[]) => Promise<boolean>\n /** 请求前回调 */\n beforeRequest?: () => Promise<void> | void\n /** 请求成功回调 */\n onSuccess?: (result: {\n type: 'local' | 'remote'\n result: Awaited<ReturnType<T>>\n }) => void\n /** 请求错误回调 */\n onError?: (error: any) => void\n /** 远程请求错误处理 */\n errorHandler?: (error: any) => any\n // /** 缓存更新回调 */\n // onCacheUpdate?: (\n // result: Awaited<ReturnType<T>>,\n // cacheData: CacheItem<T>,\n // ) => void;\n}\n\ninterface CacheUpdateEvent<T extends (...args: any[]) => Promise<any>> {\n result: Awaited<ReturnType<T>>\n cacheData: CacheItem<T>\n isCacheHit: boolean\n}\n\nfunction createQueryWithCache<T extends (...args: any[]) => Promise<any>>(\n key: string,\n fn: T,\n options?: CacheOptions<T>,\n) {\n const {\n deps,\n retry,\n maxAge,\n version,\n compareBeforeUpdate,\n remoteMemoryCache,\n equals,\n cacheEnabled,\n beforeRequest,\n onSuccess,\n onError,\n errorHandler,\n } = {\n deps: [],\n retry: 0,\n equals: deepEquals,\n compareBeforeUpdate: deepEquals,\n remoteMemoryCache: false,\n ...options,\n } satisfies CacheOptions<T>\n\n let fnRunCount = 0\n const cacheUpdateSubject = new ReplaySubject<CacheUpdateEvent<T>>(1)\n\n /** 解析 deps,如果元素是函数则调用获取值 */\n const resolveDeps = () => (typeof deps === 'function' ? deps() : deps)\n\n interface QueryOption { runCount: number, deps: readonly unknown[] }\n\n const queryFnEnhancer = (\n fn: (args: Parameters<T>, option: QueryOption) => Promise<ReturnType<T>>,\n options: Pick<CacheOptions<T>, 'onSuccess' | 'onError'> & { type: 'remote' | 'local' },\n ) => (((args, rest) => {\n const promiseResult = fn(args, rest)\n\n promiseResult\n .then((result) => {\n const res = { type: options.type, result: result as Awaited<ReturnType<T>> }\n rest.runCount === fnRunCount && options.onSuccess?.(res)\n return res\n }, (error) => {\n rest.runCount === fnRunCount && options.onError?.(error)\n })\n .catch(() => {})\n\n return promiseResult\n }) as typeof fn)\n\n const getLocalCache = async (_args: Parameters<T>, { deps }: QueryOption) => {\n const cache = await db.getItem<CacheItem<T>>(key)\n if (\n cache\n && (!version || cache.version === version)\n && (!cache.expires || cache.expires > Date.now())\n && equals(cache.deps, deps)\n ) {\n return cache.result\n }\n\n throw new Error('Cache not found')\n }\n\n const remoteResultCache: {\n success: boolean\n deps: readonly unknown[]\n result: ReturnType<T> | null\n } = {\n success: false,\n deps: [],\n result: null,\n }\n\n const clearMemoryCache = () => {\n remoteResultCache.success = false\n remoteResultCache.result = null\n remoteResultCache.deps = []\n }\n\n const queryWithMemoryCache = (args: Parameters<T>, deps: readonly unknown[]) => {\n if (!remoteMemoryCache) {\n return {\n type: 'remote' as const,\n promiseResult: fnRunner(\n () => fn(...args),\n retry,\n ),\n }\n }\n\n if (\n remoteResultCache.success\n && equals(remoteResultCache.deps, deps)\n ) {\n return {\n type: 'memory' as const,\n promiseResult: remoteResultCache.result!,\n }\n }\n\n remoteResultCache.deps = deps\n remoteResultCache.success = true\n const result = (remoteResultCache.result = fnRunner(\n () => fn(...args),\n retry,\n ) as ReturnType<T>)\n\n Promise.resolve(result)\n .catch(clearMemoryCache)\n\n return { type: 'remote' as const, promiseResult: result }\n }\n\n const queryRemote = async (args: Parameters<T>, queryOption: QueryOption) => {\n const rs = {\n type: 'remote' as const,\n result: null as unknown as Awaited<ReturnType<T>>,\n }\n const { runCount, deps } = queryOption\n try {\n const { type, promiseResult } = queryWithMemoryCache(args, deps)\n const result = (rs.result = await promiseResult)\n\n // 设置缓存\n runCount === fnRunCount\n && type === 'remote'\n && (!cacheEnabled || (await cacheEnabled(deps)))\n && Promise.resolve().then(async () => {\n const oldCache = await getLocalCache(args, queryOption).catch(() => null)\n\n const cacheData: CacheItem<T> = {\n deps: deps as any[],\n result,\n ...(version && { version }),\n ...(maxAge && { expires: Date.now() + maxAge }),\n }\n db.setItem(key, cacheData)\n\n // 如果配置了比较,且旧缓存存在且与新结果相等,则不触发 onCacheUpdate\n if (\n compareBeforeUpdate\n && oldCache\n && compareBeforeUpdate(oldCache, result)\n ) {\n return\n }\n cacheUpdateSubject.next({\n result,\n cacheData,\n isCacheHit: !!oldCache,\n })\n })\n }\n catch (error) {\n if (errorHandler) {\n rs.result = (await errorHandler(error)) as Awaited<ReturnType<T>>\n }\n else {\n throw error\n }\n }\n\n return rs.result\n }\n\n const _fn = async (...args: Parameters<T>) => {\n await beforeRequest?.()\n\n const runCount = ++fnRunCount\n\n const currentDeps = args.concat(resolveDeps())\n\n const queryOption: QueryOption = { runCount, deps: currentDeps }\n const isCacheDisabled = cacheEnabled && !(await cacheEnabled(currentDeps))\n\n const [cacheResult, remoteResult] = [\n isCacheDisabled\n ? null\n : queryFnEnhancer(getLocalCache, { type: 'local' as const, onSuccess })(args, queryOption),\n queryFnEnhancer(queryRemote, { type: 'remote' as const, onSuccess, onError })(args, queryOption),\n ]\n\n const result = cacheResult\n ? await Promise.race([\n cacheResult.catch(() => remoteResult),\n remoteResult,\n ])\n : remoteResult\n\n return result\n }\n\n _fn.refresh = async (...args: Parameters<T>) => {\n await beforeRequest?.()\n\n const runCount = ++fnRunCount\n const currentDeps = args.concat(resolveDeps())\n\n const queryOption: QueryOption = { runCount, deps: currentDeps }\n return queryFnEnhancer(\n queryRemote,\n { type: 'remote' as const, onSuccess, onError },\n )(args, queryOption)\n }\n\n _fn.getCache = () => db.getItem<CacheItem<T>>(key)\n\n _fn.updateCache = async (\n value: CacheItem<T> | ((prev: CacheItem<T> | null) => CacheItem<T> | Promise<CacheItem<T>>),\n ) => {\n if (typeof value === 'function') {\n const prevCache = await _fn.getCache().catch(() => null)\n const newCache = await value(prevCache)\n await db.setItem(key, newCache)\n }\n else {\n await db.setItem(key, value)\n }\n }\n\n _fn.subscribeCacheUpdate = (fn: (data: CacheUpdateEvent<T>) => void) =>\n cacheUpdateSubject.subscribe(fn)\n\n _fn.clearCache = async () => {\n clearMemoryCache()\n await db.removeItem(key)\n }\n\n return _fn\n}\n\n/**\n * 使用自定义数据库实例\n * @param newDb 数据库实例或 storeName,如果为字符串,则使用 localforage 创建一个实例\n */\ncreateQueryWithCache.useDb = <T extends string>(\n newDb: DBType | (T extends 'main-store' ? never : T),\n) => {\n if (typeof newDb === 'string') {\n db = localforage.createInstance({\n name: DB_NAME,\n storeName: newDb,\n })\n }\n else {\n db = newDb\n }\n}\n\nexport { createQueryWithCache }\nexport type { CacheItem, CacheOptions, CacheUpdateEvent }\n","import type { CacheOptions } from '../../utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { createQueryWithCache } from '../../utils'\nimport { useLaziedConst } from '../useLaziedConst'\n\ninterface UseQueryWithCacheOptions<T> {\n /**\n * 是否自动执行查询\n * @default true\n */\n enabled?: boolean\n /** 初始数据,支持函数形式(惰性初始化) */\n initialData?: T | (() => T)\n /** 成功回调 */\n onSuccess?: (data: T) => void\n /** 错误回调 */\n onError?: (error: any) => void\n /** 完成回调 */\n onFinished?: (result: {\n success: true\n data: T\n } | {\n success: false\n error: any\n }) => void\n /** 自定义 useEffect 钩子 */\n useCustomEffect?: typeof useEffect\n}\n\n// eslint-disable-next-line no-restricted-syntax\nexport const enum FETCHING_STATUS {\n /** 初始的空闲状态 */\n IDLE = 0b10,\n\n /** 请求中 */\n PENDING = 0b100,\n /** 初始化请求中 */\n INITIALIZING = 0b101,\n\n SUCCESS = 0b1000,\n LOCAL_SUCCESS = 0b1001,\n\n ERROR = 0b10000,\n}\n\n/**\n * 基于 createQueryWithCache 的 React Hook\n *\n * @param key - 缓存的唯一标识,暂不支持加入任何变量,仅支持字符串常量\n * @param fn - 查询函数\n * @param deps - 依赖列表,当依赖变化时重新执行查询\n * @param options - 配置选项\n */\nfunction useQueryWithCache<\n T extends () => Promise<any>,\n D,\n>(\n key: string,\n fn: T,\n deps: readonly D[] = [],\n options?: UseQueryWithCacheOptions<Awaited<ReturnType<T>>>\n & Pick<CacheOptions<T>, 'maxAge'\n | 'version'\n | 'retry'\n | 'compareBeforeUpdate'\n | 'remoteMemoryCache'> & {\n equals?: (prev: readonly D[], next: readonly D[]) => boolean\n cacheEnabled?: (deps: readonly D[]) => Promise<boolean>\n },\n) {\n type Result = Awaited<ReturnType<T>>\n\n const {\n enabled = true,\n initialData,\n onSuccess,\n onError,\n onFinished,\n useCustomEffect = useEffect,\n ...restOptions\n } = options || {}\n\n const [status, setStatus] = useState(FETCHING_STATUS.IDLE)\n const [state, setState] = useState<{\n source: 'local' | 'remote'\n data: Result | undefined\n dataUpdatedAt?: number\n error: any\n errorUpdatedAt?: number\n }>(() => ({\n source: 'local',\n data: typeof initialData === 'function' ? (initialData as () => Result)() : initialData,\n error: null,\n }))\n\n const infoRef = useRef({ deps, fn, onSuccess, onError, onFinished })\n infoRef.current.deps = deps\n infoRef.current.fn = fn\n infoRef.current.onSuccess = onSuccess\n infoRef.current.onError = onError\n infoRef.current.onFinished = onFinished\n\n const cachedFn = useLaziedConst(() => createQueryWithCache(key, () => infoRef.current.fn(), {\n // 这里类型已经推导的 T 就会出问题,先 as any 解决\n ...(restOptions as any),\n deps: () => infoRef.current.deps,\n beforeRequest: () => {\n setStatus(s => s === FETCHING_STATUS.IDLE\n ? FETCHING_STATUS.INITIALIZING\n : FETCHING_STATUS.PENDING)\n },\n onSuccess: (result) => {\n setStatus(result.type === 'local' ? FETCHING_STATUS.LOCAL_SUCCESS : FETCHING_STATUS.SUCCESS)\n setState(s => ({\n ...s,\n source: result.type,\n data: result.result,\n error: null,\n dataUpdatedAt: Date.now(),\n }))\n infoRef.current.onSuccess?.(result.result)\n infoRef.current.onFinished?.({ success: true, data: result.result })\n },\n onError: (error) => {\n setStatus(FETCHING_STATUS.ERROR)\n setState(s => ({\n ...s,\n error,\n errorUpdatedAt: Date.now(),\n }))\n infoRef.current.onError?.(error)\n infoRef.current.onFinished?.({ success: false, error })\n },\n }))\n\n useCustomEffect(() => {\n if (!enabled)\n return\n\n cachedFn()\n }, [enabled, ...deps])\n\n return {\n ...state,\n initializing: status === FETCHING_STATUS.INITIALIZING,\n loading: !!(status & FETCHING_STATUS.PENDING),\n isSuccess: !!(status & FETCHING_STATUS.SUCCESS),\n isError: status === FETCHING_STATUS.ERROR,\n setState,\n run: cachedFn,\n refresh: cachedFn.refresh,\n clearCache: cachedFn.clearCache,\n }\n}\n\nexport { useQueryWithCache }\nexport type { UseQueryWithCacheOptions }\n"]}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
|
|
1
4
|
declare class ReplaySubject<T> {
|
|
2
5
|
private maxBufferSize;
|
|
3
6
|
private buffer;
|
|
@@ -8,6 +11,10 @@ declare class ReplaySubject<T> {
|
|
|
8
11
|
next(data: T): void;
|
|
9
12
|
}
|
|
10
13
|
|
|
14
|
+
declare function useLaziedConst<T extends NonNullable<unknown>>(value: () => T): T;
|
|
15
|
+
|
|
16
|
+
declare function useLaziedRef<T extends NonNullable<unknown>>(value: () => T): React.MutableRefObject<T>;
|
|
17
|
+
|
|
11
18
|
type DBType = Pick<LocalForage, 'getItem' | 'setItem' | 'removeItem' | 'clear'>;
|
|
12
19
|
interface CacheItem<T extends (...args: any[]) => Promise<any>> {
|
|
13
20
|
/** 缓存参数 */
|
|
@@ -47,14 +54,13 @@ interface CacheOptions<T extends (...args: any[]) => Promise<any>> {
|
|
|
47
54
|
remoteMemoryCache?: boolean;
|
|
48
55
|
/**
|
|
49
56
|
* 比较依赖项(函数参数及 deps)是否相等
|
|
50
|
-
* @default
|
|
57
|
+
* @default R.equals
|
|
51
58
|
*/
|
|
52
59
|
equals?: (prev: readonly unknown[], next: readonly unknown[]) => boolean;
|
|
53
60
|
/**
|
|
54
|
-
*
|
|
55
|
-
* 不传的话默认启用缓存
|
|
61
|
+
* 根据入参决定是否启用缓存
|
|
56
62
|
*/
|
|
57
|
-
cacheEnabled?: (
|
|
63
|
+
cacheEnabled?: (deps: readonly unknown[]) => Promise<boolean>;
|
|
58
64
|
/** 请求前回调 */
|
|
59
65
|
beforeRequest?: () => Promise<void> | void;
|
|
60
66
|
/** 请求成功回调 */
|
|
@@ -76,7 +82,7 @@ declare function createQueryWithCache<T extends (...args: any[]) => Promise<any>
|
|
|
76
82
|
(...args: Parameters<T>): Promise<ReturnType<T>>;
|
|
77
83
|
refresh(...args: Parameters<T>): Promise<ReturnType<T>>;
|
|
78
84
|
getCache(): Promise<CacheItem<T> | null>;
|
|
79
|
-
updateCache(value:
|
|
85
|
+
updateCache(value: CacheItem<T> | ((prev: CacheItem<T> | null) => CacheItem<T> | Promise<CacheItem<T>>)): Promise<void>;
|
|
80
86
|
subscribeCacheUpdate(fn: (data: CacheUpdateEvent<T>) => void): () => void;
|
|
81
87
|
clearCache(): Promise<void>;
|
|
82
88
|
};
|
|
@@ -86,4 +92,78 @@ declare namespace createQueryWithCache {
|
|
|
86
92
|
|
|
87
93
|
declare function fnRunner<T extends (...args: any[]) => Promise<any>>(fn: T, retryTimes?: number): Promise<Awaited<ReturnType<T>>>;
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
interface UseQueryWithCacheOptions<T> {
|
|
96
|
+
/**
|
|
97
|
+
* 是否自动执行查询
|
|
98
|
+
* @default true
|
|
99
|
+
*/
|
|
100
|
+
enabled?: boolean;
|
|
101
|
+
/** 初始数据,支持函数形式(惰性初始化) */
|
|
102
|
+
initialData?: T | (() => T);
|
|
103
|
+
/** 成功回调 */
|
|
104
|
+
onSuccess?: (data: T) => void;
|
|
105
|
+
/** 错误回调 */
|
|
106
|
+
onError?: (error: any) => void;
|
|
107
|
+
/** 完成回调 */
|
|
108
|
+
onFinished?: (result: {
|
|
109
|
+
success: true;
|
|
110
|
+
data: T;
|
|
111
|
+
} | {
|
|
112
|
+
success: false;
|
|
113
|
+
error: any;
|
|
114
|
+
}) => void;
|
|
115
|
+
/** 自定义 useEffect 钩子 */
|
|
116
|
+
useCustomEffect?: typeof useEffect;
|
|
117
|
+
}
|
|
118
|
+
declare const enum FETCHING_STATUS {
|
|
119
|
+
/** 初始的空闲状态 */
|
|
120
|
+
IDLE = 2,
|
|
121
|
+
/** 请求中 */
|
|
122
|
+
PENDING = 4,
|
|
123
|
+
/** 初始化请求中 */
|
|
124
|
+
INITIALIZING = 5,
|
|
125
|
+
SUCCESS = 8,
|
|
126
|
+
LOCAL_SUCCESS = 9,
|
|
127
|
+
ERROR = 16
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 基于 createQueryWithCache 的 React Hook
|
|
131
|
+
*
|
|
132
|
+
* @param key - 缓存的唯一标识,暂不支持加入任何变量,仅支持字符串常量
|
|
133
|
+
* @param fn - 查询函数
|
|
134
|
+
* @param deps - 依赖列表,当依赖变化时重新执行查询
|
|
135
|
+
* @param options - 配置选项
|
|
136
|
+
*/
|
|
137
|
+
declare function useQueryWithCache<T extends () => Promise<any>, D>(key: string, fn: T, deps?: readonly D[], options?: UseQueryWithCacheOptions<Awaited<ReturnType<T>>> & Pick<CacheOptions<T>, 'maxAge' | 'version' | 'retry' | 'compareBeforeUpdate' | 'remoteMemoryCache'> & {
|
|
138
|
+
equals?: (prev: readonly D[], next: readonly D[]) => boolean;
|
|
139
|
+
cacheEnabled?: (deps: readonly D[]) => Promise<boolean>;
|
|
140
|
+
}): {
|
|
141
|
+
initializing: boolean;
|
|
142
|
+
loading: boolean;
|
|
143
|
+
isSuccess: boolean;
|
|
144
|
+
isError: boolean;
|
|
145
|
+
setState: react.Dispatch<react.SetStateAction<{
|
|
146
|
+
source: "local" | "remote";
|
|
147
|
+
data: Awaited<ReturnType<T>> | undefined;
|
|
148
|
+
dataUpdatedAt?: number;
|
|
149
|
+
error: any;
|
|
150
|
+
errorUpdatedAt?: number;
|
|
151
|
+
}>>;
|
|
152
|
+
run: {
|
|
153
|
+
(): Promise<Promise<any>>;
|
|
154
|
+
refresh(): Promise<Promise<any>>;
|
|
155
|
+
getCache(): Promise<CacheItem<() => Promise<any>> | null>;
|
|
156
|
+
updateCache(value: CacheItem<() => Promise<any>> | ((prev: CacheItem<() => Promise<any>> | null) => CacheItem<() => Promise<any>> | Promise<CacheItem<() => Promise<any>>>)): Promise<void>;
|
|
157
|
+
subscribeCacheUpdate(fn: (data: CacheUpdateEvent<() => Promise<any>>) => void): () => void;
|
|
158
|
+
clearCache(): Promise<void>;
|
|
159
|
+
};
|
|
160
|
+
refresh: () => Promise<Promise<any>>;
|
|
161
|
+
clearCache: () => Promise<void>;
|
|
162
|
+
source: "local" | "remote";
|
|
163
|
+
data: Awaited<ReturnType<T>> | undefined;
|
|
164
|
+
dataUpdatedAt?: number;
|
|
165
|
+
error: any;
|
|
166
|
+
errorUpdatedAt?: number;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export { type CacheItem, type CacheOptions, type CacheUpdateEvent, FETCHING_STATUS, ReplaySubject, type UseQueryWithCacheOptions, createQueryWithCache, fnRunner, useLaziedConst, useLaziedRef, useQueryWithCache };
|