@choksheak/react-utils 0.2.7 → 0.2.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/package.json +50 -2
- package/sharedQuery.cjs +146 -191
- package/sharedQuery.d.mts +72 -12
- package/sharedQuery.d.ts +69 -10
- package/sharedQuery.min.cjs +1 -1
- package/sharedQuery.min.cjs.map +1 -1
- package/sharedQuery.min.mjs +1 -1
- package/sharedQuery.min.mjs.map +1 -1
- package/sharedQuery.mjs +151 -191
- package/sharedState.cjs +50 -103
- package/sharedState.d.mts +12 -7
- package/sharedState.d.ts +10 -6
- package/sharedState.min.cjs +1 -1
- package/sharedState.min.cjs.map +1 -1
- package/sharedState.min.mjs +1 -1
- package/sharedState.min.mjs.map +1 -1
- package/sharedState.mjs +48 -102
- package/storage.cjs +67 -0
- package/storage.d.mts +19 -0
- package/storage.d.ts +16 -0
- package/storage.min.cjs +2 -0
- package/storage.min.cjs.map +1 -0
- package/storage.min.mjs +2 -0
- package/storage.min.mjs.map +1 -0
- package/storage.mjs +42 -0
- package/{utils/stringify.cjs → stringify.cjs} +1 -1
- package/stringify.min.cjs.map +1 -0
- package/stringify.min.mjs.map +1 -0
- package/{utils/stringify.mjs → stringify.mjs} +1 -1
- package/{utils/useDeepMemo.cjs → useDeepMemo.cjs} +1 -1
- package/useDeepMemo.d.mts +7 -0
- package/useDeepMemo.d.ts +5 -0
- package/useDeepMemo.min.cjs.map +1 -0
- package/useDeepMemo.min.mjs.map +1 -0
- package/{utils/useDeepMemo.mjs → useDeepMemo.mjs} +1 -1
- package/utils/storage.cjs +0 -162
- package/utils/storage.d.mts +0 -46
- package/utils/storage.d.ts +0 -44
- package/utils/storage.min.cjs +0 -2
- package/utils/storage.min.cjs.map +0 -1
- package/utils/storage.min.mjs +0 -2
- package/utils/storage.min.mjs.map +0 -1
- package/utils/storage.mjs +0 -134
- package/utils/stringify.min.cjs.map +0 -1
- package/utils/stringify.min.mjs.map +0 -1
- package/utils/useDeepMemo.d.mts +0 -4
- package/utils/useDeepMemo.d.ts +0 -2
- package/utils/useDeepMemo.min.cjs.map +0 -1
- package/utils/useDeepMemo.min.mjs.map +0 -1
- /package/{utils/stringify.d.mts → stringify.d.mts} +0 -0
- /package/{utils/stringify.d.ts → stringify.d.ts} +0 -0
- /package/{utils/stringify.min.cjs → stringify.min.cjs} +0 -0
- /package/{utils/stringify.min.mjs → stringify.min.mjs} +0 -0
- /package/{utils/useDeepMemo.min.cjs → useDeepMemo.min.cjs} +0 -0
- /package/{utils/useDeepMemo.min.mjs → useDeepMemo.min.mjs} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@choksheak/react-utils",
|
|
3
3
|
"license": "The Unlicense",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.9",
|
|
5
5
|
"description": "Miscellaneous React+TypeScript utilities with support for full tree-shaking.",
|
|
6
6
|
"private": false,
|
|
7
7
|
"files": [
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"wretch": "^3.0.2"
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
|
-
"@choksheak/ts-utils": ">=0.
|
|
98
|
+
"@choksheak/ts-utils": ">=0.3.1",
|
|
99
99
|
"lodash": ">=4.17.21",
|
|
100
100
|
"object-sizeof": ">=2.6.5",
|
|
101
101
|
"react": ">=16",
|
|
@@ -142,6 +142,45 @@
|
|
|
142
142
|
"development": "./sharedState.cjs",
|
|
143
143
|
"default": "./sharedState.cjs"
|
|
144
144
|
}
|
|
145
|
+
},
|
|
146
|
+
"./storage": {
|
|
147
|
+
"types": "./storage.d.ts",
|
|
148
|
+
"import": {
|
|
149
|
+
"production": "./storage.min.mjs",
|
|
150
|
+
"development": "./storage.mjs",
|
|
151
|
+
"default": "./storage.mjs"
|
|
152
|
+
},
|
|
153
|
+
"require": {
|
|
154
|
+
"production": "./storage.min.cjs",
|
|
155
|
+
"development": "./storage.cjs",
|
|
156
|
+
"default": "./storage.cjs"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"./stringify": {
|
|
160
|
+
"types": "./stringify.d.ts",
|
|
161
|
+
"import": {
|
|
162
|
+
"production": "./stringify.min.mjs",
|
|
163
|
+
"development": "./stringify.mjs",
|
|
164
|
+
"default": "./stringify.mjs"
|
|
165
|
+
},
|
|
166
|
+
"require": {
|
|
167
|
+
"production": "./stringify.min.cjs",
|
|
168
|
+
"development": "./stringify.cjs",
|
|
169
|
+
"default": "./stringify.cjs"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"./useDeepMemo": {
|
|
173
|
+
"types": "./useDeepMemo.d.ts",
|
|
174
|
+
"import": {
|
|
175
|
+
"production": "./useDeepMemo.min.mjs",
|
|
176
|
+
"development": "./useDeepMemo.mjs",
|
|
177
|
+
"default": "./useDeepMemo.mjs"
|
|
178
|
+
},
|
|
179
|
+
"require": {
|
|
180
|
+
"production": "./useDeepMemo.min.cjs",
|
|
181
|
+
"development": "./useDeepMemo.cjs",
|
|
182
|
+
"default": "./useDeepMemo.cjs"
|
|
183
|
+
}
|
|
145
184
|
}
|
|
146
185
|
},
|
|
147
186
|
"typesVersions": {
|
|
@@ -154,6 +193,15 @@
|
|
|
154
193
|
],
|
|
155
194
|
"sharedState": [
|
|
156
195
|
"./sharedState.d.ts"
|
|
196
|
+
],
|
|
197
|
+
"storage": [
|
|
198
|
+
"./storage.d.ts"
|
|
199
|
+
],
|
|
200
|
+
"stringify": [
|
|
201
|
+
"./stringify.d.ts"
|
|
202
|
+
],
|
|
203
|
+
"useDeepMemo": [
|
|
204
|
+
"./useDeepMemo.d.ts"
|
|
157
205
|
]
|
|
158
206
|
}
|
|
159
207
|
}
|
package/sharedQuery.cjs
CHANGED
|
@@ -31,7 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var sharedQuery_exports = {};
|
|
32
32
|
__export(sharedQuery_exports, {
|
|
33
33
|
SharedQuery: () => SharedQuery,
|
|
34
|
-
|
|
34
|
+
SharedQueryConfig: () => SharedQueryConfig,
|
|
35
|
+
configureSharedQuery: () => configureSharedQuery,
|
|
35
36
|
sharedQuery: () => sharedQuery,
|
|
36
37
|
useSharedQuery: () => useSharedQuery
|
|
37
38
|
});
|
|
@@ -44,108 +45,48 @@ var import_react3 = require("react");
|
|
|
44
45
|
var import_timeConstants = require("@choksheak/ts-utils/timeConstants");
|
|
45
46
|
var import_react = require("react");
|
|
46
47
|
|
|
47
|
-
// src/
|
|
48
|
+
// src/storage.ts
|
|
48
49
|
var import_kvStore = require("@choksheak/ts-utils/kvStore");
|
|
50
|
+
var import_localStore = require("@choksheak/ts-utils/localStore");
|
|
49
51
|
function getStorageAdapter(options, defaultStoreExpiryMs) {
|
|
50
|
-
const {
|
|
51
|
-
if (store) {
|
|
52
|
-
return
|
|
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
|
-
load(key) {
|
|
80
|
-
if (typeof window === "undefined") return void 0;
|
|
81
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
82
|
-
const raw = window.localStorage.getItem(fullKey);
|
|
83
|
-
if (!raw) return void 0;
|
|
84
|
-
try {
|
|
85
|
-
const box = JSON.parse(raw);
|
|
86
|
-
if (!box || box.expiresAt && Date.now() >= box.expiresAt) {
|
|
87
|
-
window.localStorage.removeItem(fullKey);
|
|
88
|
-
return void 0;
|
|
89
|
-
}
|
|
90
|
-
return box.value;
|
|
91
|
-
} catch {
|
|
92
|
-
window.localStorage.removeItem(fullKey);
|
|
93
|
-
return void 0;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
delete(key) {
|
|
97
|
-
if (typeof window === "undefined") return;
|
|
98
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
99
|
-
window.localStorage.removeItem(fullKey);
|
|
100
|
-
}
|
|
101
|
-
clear() {
|
|
102
|
-
if (typeof window === "undefined") return;
|
|
103
|
-
for (const key of Object.keys(window.localStorage)) {
|
|
104
|
-
if (key.startsWith(this.keyPrefix)) {
|
|
105
|
-
window.localStorage.removeItem(key);
|
|
52
|
+
const { store } = options ?? {};
|
|
53
|
+
if (!store) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if ("persistTo" in store && typeof store.persistTo === "string" && "key" in store && typeof store.key === "string") {
|
|
57
|
+
const expiryMs = store.expiryMs || defaultStoreExpiryMs;
|
|
58
|
+
switch (store.persistTo) {
|
|
59
|
+
case "localStorage":
|
|
60
|
+
return new import_localStore.LocalStore(store.key, {
|
|
61
|
+
defaultExpiryMs: expiryMs
|
|
62
|
+
}).asStorageAdapter();
|
|
63
|
+
case "indexedDb": {
|
|
64
|
+
const keyPrefix = store.key + ":";
|
|
65
|
+
return {
|
|
66
|
+
set: async (key, value) => {
|
|
67
|
+
await import_kvStore.kvStore.set(keyPrefix + key, value, expiryMs);
|
|
68
|
+
},
|
|
69
|
+
get: async (key) => {
|
|
70
|
+
return await import_kvStore.kvStore.get(keyPrefix + key);
|
|
71
|
+
},
|
|
72
|
+
delete: async (key) => {
|
|
73
|
+
await import_kvStore.kvStore.delete(keyPrefix + key);
|
|
74
|
+
},
|
|
75
|
+
clear: async () => {
|
|
76
|
+
await import_kvStore.kvStore.clear();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
106
79
|
}
|
|
80
|
+
default:
|
|
81
|
+
store.persistTo;
|
|
82
|
+
throw new Error(`Unknown store.adapter ${store.persistTo}`);
|
|
107
83
|
}
|
|
108
84
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
constructor(keyPrefix, expiryMs) {
|
|
112
|
-
this.keyPrefix = keyPrefix;
|
|
113
|
-
this.expiryMs = expiryMs;
|
|
114
|
-
}
|
|
115
|
-
async save(key, value) {
|
|
116
|
-
if (typeof window === "undefined") return;
|
|
117
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
118
|
-
await import_kvStore.kvStore.set(fullKey, JSON.stringify(value), this.expiryMs);
|
|
119
|
-
}
|
|
120
|
-
async load(key) {
|
|
121
|
-
if (typeof window === "undefined") return void 0;
|
|
122
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
123
|
-
const raw = await import_kvStore.kvStore.get(fullKey);
|
|
124
|
-
if (raw === void 0) return void 0;
|
|
125
|
-
try {
|
|
126
|
-
return JSON.parse(raw);
|
|
127
|
-
} catch {
|
|
128
|
-
await import_kvStore.kvStore.delete(fullKey);
|
|
129
|
-
return void 0;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
async delete(key) {
|
|
133
|
-
if (typeof window === "undefined") return;
|
|
134
|
-
const fullKey = this.keyPrefix + ":" + key;
|
|
135
|
-
await import_kvStore.kvStore.delete(fullKey);
|
|
136
|
-
}
|
|
137
|
-
async clear() {
|
|
138
|
-
if (typeof window === "undefined") return;
|
|
139
|
-
await import_kvStore.kvStore.forEach(async (k) => {
|
|
140
|
-
if (k.startsWith(this.keyPrefix)) {
|
|
141
|
-
await import_kvStore.kvStore.delete(k);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
};
|
|
85
|
+
return store;
|
|
86
|
+
}
|
|
146
87
|
|
|
147
88
|
// src/sharedState.ts
|
|
148
|
-
var
|
|
89
|
+
var SharedStateConfig = {
|
|
149
90
|
/**
|
|
150
91
|
* Default duration for storage expiration in milliseconds. Initial value
|
|
151
92
|
* is 30 days, but can be changed to anything.
|
|
@@ -212,12 +153,14 @@ var SharedState = class {
|
|
|
212
153
|
this.pubSubKey = String(stateKey++);
|
|
213
154
|
this.storageAdapter = getStorageAdapter(
|
|
214
155
|
options,
|
|
215
|
-
|
|
156
|
+
SharedStateConfig.storeExpiryMs
|
|
216
157
|
);
|
|
217
|
-
this.setValueBounded = (
|
|
158
|
+
this.setValueBounded = (next) => {
|
|
159
|
+
this.setValue(next);
|
|
160
|
+
};
|
|
218
161
|
pubSubStore.setNoNotify(this.pubSubKey, defaultValue);
|
|
219
162
|
const lazyLoad = options?.lazyLoad;
|
|
220
|
-
const lazy = lazyLoad !== void 0 ? lazyLoad :
|
|
163
|
+
const lazy = lazyLoad !== void 0 ? lazyLoad : SharedStateConfig.lazyLoad;
|
|
221
164
|
if (!lazy) {
|
|
222
165
|
void this.initDefaultValueOnce();
|
|
223
166
|
}
|
|
@@ -242,19 +185,19 @@ var SharedState = class {
|
|
|
242
185
|
next = next(prev);
|
|
243
186
|
}
|
|
244
187
|
pubSubStore.set(this.pubSubKey, next);
|
|
245
|
-
void this.storageAdapter?.
|
|
188
|
+
void this.storageAdapter?.set(STORAGE_KEY, next);
|
|
246
189
|
}
|
|
247
190
|
// Remove the value of the shared state. Actually this just sets the value
|
|
248
191
|
// back to the given default value.
|
|
249
192
|
delete() {
|
|
250
193
|
pubSubStore.set(this.pubSubKey, this.defaultValue);
|
|
251
|
-
void this.storageAdapter?.
|
|
194
|
+
void this.storageAdapter?.set(STORAGE_KEY, this.defaultValue);
|
|
252
195
|
}
|
|
253
196
|
// Initial default handling
|
|
254
197
|
async initDefaultValueOnce() {
|
|
255
198
|
if (this.initDone) return;
|
|
256
199
|
this.initDone = true;
|
|
257
|
-
const v = await this.storageAdapter?.
|
|
200
|
+
const v = await this.storageAdapter?.get(STORAGE_KEY);
|
|
258
201
|
pubSubStore.set(this.pubSubKey, v !== void 0 ? v : this.defaultValue);
|
|
259
202
|
}
|
|
260
203
|
};
|
|
@@ -272,7 +215,7 @@ function useSharedState(state) {
|
|
|
272
215
|
return [value, state.setValueBounded];
|
|
273
216
|
}
|
|
274
217
|
|
|
275
|
-
// src/
|
|
218
|
+
// src/stringify.ts
|
|
276
219
|
function stringifyDeterministicForKeys(params) {
|
|
277
220
|
const cache = /* @__PURE__ */ new Set();
|
|
278
221
|
return JSON.stringify(params, (_, value) => {
|
|
@@ -303,7 +246,7 @@ function stringifyDeterministicForKeys(params) {
|
|
|
303
246
|
});
|
|
304
247
|
}
|
|
305
248
|
|
|
306
|
-
// src/
|
|
249
|
+
// src/useDeepMemo.ts
|
|
307
250
|
var import_isEqual = __toESM(require("lodash/isEqual"));
|
|
308
251
|
var import_react2 = require("react");
|
|
309
252
|
function useDeepMemo(value) {
|
|
@@ -318,22 +261,25 @@ function useDeepMemo(value) {
|
|
|
318
261
|
}
|
|
319
262
|
|
|
320
263
|
// src/sharedQuery.ts
|
|
321
|
-
var
|
|
322
|
-
|
|
264
|
+
var SharedQueryConfig = {
|
|
265
|
+
/** Refetch on every page load. */
|
|
323
266
|
staleMs: 0,
|
|
324
|
-
|
|
267
|
+
/** Keep in cache for a long time. */
|
|
325
268
|
expiryMs: 30 * import_timeConstants2.MS_PER_DAY,
|
|
326
|
-
|
|
269
|
+
/** Always refetch automatically if the data is stale. */
|
|
327
270
|
refetchOnStale: true,
|
|
328
|
-
|
|
271
|
+
/** No default persistence configured. */
|
|
329
272
|
persistTo: void 0,
|
|
330
|
-
|
|
273
|
+
/** 100 is not too large, but please tweak accordingly. */
|
|
331
274
|
maxSize: 100,
|
|
332
|
-
|
|
275
|
+
/** 100kb limit before discarding old records. */
|
|
333
276
|
maxBytes: 1e5,
|
|
334
|
-
|
|
277
|
+
/** Default to log to console. */
|
|
335
278
|
log: (...args) => console.log("[sharedQuery]", ...args)
|
|
336
279
|
};
|
|
280
|
+
function configureSharedQuery(config) {
|
|
281
|
+
Object.assign(SharedQueryConfig, config);
|
|
282
|
+
}
|
|
337
283
|
var SharedQuery = class {
|
|
338
284
|
inflightQueries = /* @__PURE__ */ new Map();
|
|
339
285
|
queryState;
|
|
@@ -350,32 +296,32 @@ var SharedQuery = class {
|
|
|
350
296
|
refetchOnStale;
|
|
351
297
|
maxSize;
|
|
352
298
|
maxBytes;
|
|
299
|
+
keepLastNonEmptyData;
|
|
353
300
|
log;
|
|
354
301
|
constructor(options) {
|
|
355
302
|
this.queryName = options.queryName;
|
|
356
303
|
this.queryFn = options.queryFn;
|
|
357
|
-
this.staleMs = options?.staleMs ??
|
|
358
|
-
this.expiryMs = options?.expiryMs ??
|
|
359
|
-
this.refetchOnStale = options?.refetchOnStale ??
|
|
360
|
-
if (!options.
|
|
361
|
-
const persistTo = options.persistTo ??
|
|
362
|
-
if (persistTo
|
|
363
|
-
options.
|
|
364
|
-
|
|
365
|
-
|
|
304
|
+
this.staleMs = options?.staleMs ?? SharedQueryConfig.staleMs;
|
|
305
|
+
this.expiryMs = options?.expiryMs ?? SharedQueryConfig.expiryMs;
|
|
306
|
+
this.refetchOnStale = options?.refetchOnStale ?? SharedQueryConfig.refetchOnStale;
|
|
307
|
+
if (!options.store) {
|
|
308
|
+
const persistTo = options.persistTo ?? SharedQueryConfig.persistTo;
|
|
309
|
+
if (persistTo) {
|
|
310
|
+
options.store = {
|
|
311
|
+
persistTo,
|
|
312
|
+
key: options.queryName,
|
|
313
|
+
expiryMs: this.expiryMs
|
|
314
|
+
};
|
|
366
315
|
}
|
|
367
316
|
}
|
|
368
|
-
this.maxSize = options?.maxSize ??
|
|
369
|
-
this.maxBytes = options?.maxBytes ??
|
|
370
|
-
this.
|
|
317
|
+
this.maxSize = options?.maxSize ?? SharedQueryConfig.maxSize;
|
|
318
|
+
this.maxBytes = options?.maxBytes ?? SharedQueryConfig.maxBytes;
|
|
319
|
+
this.keepLastNonEmptyData = Boolean(options?.keepLastNonEmptyData);
|
|
320
|
+
this.log = options?.log ?? SharedQueryConfig.log;
|
|
371
321
|
this.queryState = sharedState(
|
|
372
322
|
{},
|
|
373
323
|
// defaultValue
|
|
374
|
-
|
|
375
|
-
...options,
|
|
376
|
-
// Fallback to use expiryMs for the storeExpiryMs.
|
|
377
|
-
storeExpiryMs: options?.storeExpiryMs || this.expiryMs
|
|
378
|
-
}
|
|
324
|
+
options
|
|
379
325
|
);
|
|
380
326
|
}
|
|
381
327
|
/** Returns a key to identify requests based on the given args. */
|
|
@@ -486,7 +432,14 @@ var SharedQuery = class {
|
|
|
486
432
|
}
|
|
487
433
|
/** Get the current stored data for a query key. */
|
|
488
434
|
getData(queryKey) {
|
|
489
|
-
|
|
435
|
+
const stateValue = this.queryState.getSnapshot()?.[queryKey];
|
|
436
|
+
if (stateValue?.lastUpdatedMs) {
|
|
437
|
+
if (this.isExpired(stateValue.lastUpdatedMs)) {
|
|
438
|
+
this.deleteData(queryKey);
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return stateValue?.data;
|
|
490
443
|
}
|
|
491
444
|
/** Set the data directly if the user obtained it from somewhere else. */
|
|
492
445
|
setData(queryKey, data, dataUpdatedMs = Date.now()) {
|
|
@@ -556,70 +509,64 @@ var SharedQuery = class {
|
|
|
556
509
|
return;
|
|
557
510
|
}
|
|
558
511
|
const oldByteSize = (0, import_object_sizeof.default)(oldState);
|
|
559
|
-
let
|
|
512
|
+
let numToCut = this.maxSize ? oldSize - this.maxSize : 0;
|
|
513
|
+
let bytesToCut = this.maxBytes ? oldByteSize - this.maxBytes : 0;
|
|
514
|
+
if (numToCut <= 0 && bytesToCut <= 0) {
|
|
515
|
+
this.log(
|
|
516
|
+
`No need to trim data for ${this.queryName}: size=${oldSize} (limit=${this.maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`
|
|
517
|
+
);
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
this.log(
|
|
521
|
+
`Need to trim ${this.queryName}: numToCut=${numToCut}, bytesToCut=${bytesToCut}`
|
|
522
|
+
);
|
|
523
|
+
const newState = { ...oldState };
|
|
560
524
|
let needUpdate = false;
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
delete newState[key];
|
|
582
|
-
numToCut--;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
525
|
+
const deleteKeyIfNotMounted = (key, expired) => {
|
|
526
|
+
if (this.mountedKeys.has(key)) {
|
|
527
|
+
this.log(`Cannot clean up ${key} as it is mounted`);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const byteSize = (0, import_object_sizeof.default)(key) + (0, import_object_sizeof.default)(newState[key]);
|
|
531
|
+
this.log(
|
|
532
|
+
`Cleaning up unmounted${expired ? ", expired" : ""} ${key} (byteSize=${byteSize.toLocaleString()})`
|
|
533
|
+
);
|
|
534
|
+
numToCut--;
|
|
535
|
+
bytesToCut -= byteSize;
|
|
536
|
+
delete newState[key];
|
|
537
|
+
needUpdate = true;
|
|
538
|
+
};
|
|
539
|
+
let entriesByTimeAscending = Object.entries(newState).sort(
|
|
540
|
+
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
541
|
+
);
|
|
542
|
+
for (const [key] of entriesByTimeAscending) {
|
|
543
|
+
if (!this.isExpired(newState[key].lastUpdatedMs)) {
|
|
544
|
+
break;
|
|
585
545
|
}
|
|
546
|
+
deleteKeyIfNotMounted(key, true);
|
|
586
547
|
}
|
|
587
|
-
if (
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
if (bytesToCut > 0) {
|
|
591
|
-
this.log(
|
|
592
|
-
`enforceSizeLimit for ${this.queryName} needed due to byte size ${currentByteSize.toLocaleString()} > ${this.maxBytes.toLocaleString()}`
|
|
593
|
-
);
|
|
594
|
-
if (!needUpdate) {
|
|
595
|
-
newState = { ...newState };
|
|
596
|
-
needUpdate = true;
|
|
597
|
-
}
|
|
598
|
-
const entriesByTimeAscending = Object.entries(newState).sort(
|
|
548
|
+
if (numToCut > 0 || bytesToCut > 0) {
|
|
549
|
+
if (needUpdate) {
|
|
550
|
+
entriesByTimeAscending = Object.entries(newState).sort(
|
|
599
551
|
(entry1, entry2) => entry1[1].lastUpdatedMs - entry2[1].lastUpdatedMs
|
|
600
552
|
);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
this.log(`Cleaning up unmounted ${key}`);
|
|
607
|
-
const thisSize = (0, import_object_sizeof.default)(key) + (0, import_object_sizeof.default)(newState[key]);
|
|
608
|
-
delete newState[key];
|
|
609
|
-
bytesToCut -= thisSize;
|
|
610
|
-
}
|
|
553
|
+
}
|
|
554
|
+
for (const [key] of entriesByTimeAscending) {
|
|
555
|
+
deleteKeyIfNotMounted(key, false);
|
|
556
|
+
if (numToCut <= 0 && bytesToCut <= 0) {
|
|
557
|
+
break;
|
|
611
558
|
}
|
|
612
559
|
}
|
|
613
560
|
}
|
|
614
|
-
if (needUpdate) {
|
|
615
|
-
this.queryState.setValue(newState);
|
|
561
|
+
if (!needUpdate) {
|
|
616
562
|
this.log(
|
|
617
|
-
`
|
|
563
|
+
`No trimmable entries found for ${this.queryName}: size=${oldSize} (limit=${this.maxSize}), byteSize=${oldByteSize.toLocaleString()} (limit=${this.maxBytes.toLocaleString()})`
|
|
618
564
|
);
|
|
619
565
|
return;
|
|
620
566
|
}
|
|
567
|
+
this.queryState.setValue(newState);
|
|
621
568
|
this.log(
|
|
622
|
-
`
|
|
569
|
+
`Trimmed data for ${this.queryName}: size=[${oldSize} -> ${Object.keys(newState).length}] (limit=${this.maxSize}), byteSize=[${oldByteSize.toLocaleString()} -> ${(0, import_object_sizeof.default)(newState).toLocaleString()}] (limit=${this.maxBytes.toLocaleString()})`
|
|
623
570
|
);
|
|
624
571
|
}
|
|
625
572
|
};
|
|
@@ -635,7 +582,7 @@ var DEFAULT_QUERY_STATE_ENTRY = {
|
|
|
635
582
|
lastUpdatedMs: 0,
|
|
636
583
|
loading: true
|
|
637
584
|
};
|
|
638
|
-
function useSharedQuery(query, args
|
|
585
|
+
function useSharedQuery(query, ...args) {
|
|
639
586
|
const stableArgs = useDeepMemo(args);
|
|
640
587
|
const [queryState, setQueryState] = useSharedState(query.queryState);
|
|
641
588
|
const isMounted = (0, import_react3.useRef)(true);
|
|
@@ -643,23 +590,29 @@ function useSharedQuery(query, args = []) {
|
|
|
643
590
|
() => query.getQueryKey(stableArgs),
|
|
644
591
|
[query, stableArgs]
|
|
645
592
|
);
|
|
646
|
-
const queryStateValue = queryState[queryKey];
|
|
593
|
+
const queryStateValue = queryState[queryKey] ?? DEFAULT_QUERY_STATE_ENTRY;
|
|
647
594
|
const setQueryStateValue = (0, import_react3.useCallback)(
|
|
648
|
-
(
|
|
595
|
+
(next) => {
|
|
649
596
|
setQueryState((prev) => {
|
|
650
597
|
const clone = { ...prev };
|
|
651
|
-
clone[queryKey] = typeof
|
|
598
|
+
clone[queryKey] = typeof next === "function" ? next(clone[queryKey] ?? DEFAULT_QUERY_STATE_ENTRY) : next;
|
|
652
599
|
return clone;
|
|
653
600
|
});
|
|
654
601
|
},
|
|
655
602
|
[queryKey, setQueryState]
|
|
656
603
|
);
|
|
604
|
+
const [lastNonEmptyData, setLastNonEmptyData] = (0, import_react3.useState)();
|
|
605
|
+
(0, import_react3.useEffect)(() => {
|
|
606
|
+
if (query.keepLastNonEmptyData && queryStateValue.data !== void 0) {
|
|
607
|
+
setLastNonEmptyData(queryStateValue.data);
|
|
608
|
+
}
|
|
609
|
+
}, [query.keepLastNonEmptyData, queryStateValue.data]);
|
|
657
610
|
const execute = (0, import_react3.useCallback)(
|
|
658
611
|
async (forceRefresh) => {
|
|
659
612
|
query.log(`Begin executing shared query ${queryKey}`);
|
|
660
613
|
setQueryStateValue((prev) => ({
|
|
661
614
|
// Keep old data and error.
|
|
662
|
-
...prev
|
|
615
|
+
...prev,
|
|
663
616
|
lastUpdatedMs: Date.now(),
|
|
664
617
|
loading: true
|
|
665
618
|
}));
|
|
@@ -680,7 +633,7 @@ function useSharedQuery(query, args = []) {
|
|
|
680
633
|
const now = Date.now();
|
|
681
634
|
setQueryStateValue((prev) => ({
|
|
682
635
|
// Keep old data.
|
|
683
|
-
...prev
|
|
636
|
+
...prev,
|
|
684
637
|
lastUpdatedMs: now,
|
|
685
638
|
loading: false,
|
|
686
639
|
error: e,
|
|
@@ -701,9 +654,9 @@ function useSharedQuery(query, args = []) {
|
|
|
701
654
|
};
|
|
702
655
|
}, [execute, query, queryKey]);
|
|
703
656
|
return (0, import_react3.useMemo)(() => {
|
|
704
|
-
const state = queryStateValue ?? DEFAULT_QUERY_STATE_ENTRY;
|
|
705
657
|
return {
|
|
706
|
-
...
|
|
658
|
+
...queryStateValue,
|
|
659
|
+
lastNonEmptyData,
|
|
707
660
|
// This works only if the user-given queryFn supports abort. If not,
|
|
708
661
|
// this function doesn't do anything, since we don't have any means to
|
|
709
662
|
// abort the running queryFn.
|
|
@@ -718,7 +671,7 @@ function useSharedQuery(query, args = []) {
|
|
|
718
671
|
setData: (data, dataUpdatedMs) => {
|
|
719
672
|
const now = Date.now();
|
|
720
673
|
setQueryStateValue((prev) => ({
|
|
721
|
-
...prev
|
|
674
|
+
...prev,
|
|
722
675
|
data,
|
|
723
676
|
dataUpdatedMs: dataUpdatedMs ?? now,
|
|
724
677
|
lastUpdatedMs: now,
|
|
@@ -735,6 +688,7 @@ function useSharedQuery(query, args = []) {
|
|
|
735
688
|
};
|
|
736
689
|
}, [
|
|
737
690
|
execute,
|
|
691
|
+
lastNonEmptyData,
|
|
738
692
|
query,
|
|
739
693
|
queryKey,
|
|
740
694
|
queryStateValue,
|
|
@@ -745,7 +699,8 @@ function useSharedQuery(query, args = []) {
|
|
|
745
699
|
// Annotate the CommonJS export names for ESM import in node:
|
|
746
700
|
0 && (module.exports = {
|
|
747
701
|
SharedQuery,
|
|
748
|
-
|
|
702
|
+
SharedQueryConfig,
|
|
703
|
+
configureSharedQuery,
|
|
749
704
|
sharedQuery,
|
|
750
705
|
useSharedQuery
|
|
751
706
|
});
|