react-native-onyx 2.0.137 → 2.0.139
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/Onyx.js +51 -16
- package/dist/OnyxCache.d.ts +2 -6
- package/dist/OnyxCache.js +31 -43
- package/dist/OnyxMerge/index.js +2 -2
- package/dist/OnyxMerge/index.native.js +2 -2
- package/dist/OnyxMerge/types.d.ts +1 -1
- package/dist/OnyxUtils.d.ts +6 -6
- package/dist/OnyxUtils.js +21 -28
- package/dist/types.d.ts +2 -0
- package/dist/useOnyx.js +1 -0
- package/package.json +1 -1
package/dist/Onyx.js
CHANGED
|
@@ -155,6 +155,13 @@ function disconnect(connection) {
|
|
|
155
155
|
* @param options optional configuration object
|
|
156
156
|
*/
|
|
157
157
|
function set(key, value, options) {
|
|
158
|
+
return setInternal(key, value, options);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* @param isFromUpdate - Whether this call originates from Onyx.update()
|
|
162
|
+
* When isFromUpdate = true (called from Onyx.update()), useOnyx hook subscribers are batched to escape excessive re-renders in components
|
|
163
|
+
*/
|
|
164
|
+
function setInternal(key, value, options, isFromUpdate = false) {
|
|
158
165
|
// When we use Onyx.set to set a key we want to clear the current delta changes from Onyx.merge that were queued
|
|
159
166
|
// before the value was set. If Onyx.merge is currently reading the old value from storage, it will then not apply the changes.
|
|
160
167
|
if (OnyxUtils_1.default.hasPendingMergeForKey(key)) {
|
|
@@ -200,13 +207,13 @@ function set(key, value, options) {
|
|
|
200
207
|
const hasChanged = (options === null || options === void 0 ? void 0 : options.skipCacheCheck) ? true : OnyxCache_1.default.hasValueChanged(key, valueWithoutNestedNullValues);
|
|
201
208
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.SET, key, value, hasChanged);
|
|
202
209
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
203
|
-
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, valueWithoutNestedNullValues, hasChanged);
|
|
210
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, valueWithoutNestedNullValues, hasChanged, isFromUpdate);
|
|
204
211
|
// If the value has not changed or the key got removed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
205
212
|
if (!hasChanged) {
|
|
206
213
|
return updatePromise;
|
|
207
214
|
}
|
|
208
215
|
return storage_1.default.setItem(key, valueWithoutNestedNullValues)
|
|
209
|
-
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error,
|
|
216
|
+
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, setInternal, key, valueWithoutNestedNullValues, undefined, isFromUpdate))
|
|
210
217
|
.then(() => {
|
|
211
218
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.SET, key, valueWithoutNestedNullValues);
|
|
212
219
|
return updatePromise;
|
|
@@ -220,6 +227,13 @@ function set(key, value, options) {
|
|
|
220
227
|
* @param data object keyed by ONYXKEYS and the values to set
|
|
221
228
|
*/
|
|
222
229
|
function multiSet(data) {
|
|
230
|
+
return multiSetInternal(data);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* @param isFromUpdate - Whether this call originates from Onyx.update()
|
|
234
|
+
* When isFromUpdate = true (called from Onyx.update()), useOnyx hook subscribers are batched to escape excessive re-renders in components
|
|
235
|
+
*/
|
|
236
|
+
function multiSetInternal(data, isFromUpdate = false) {
|
|
223
237
|
let newData = data;
|
|
224
238
|
const skippableCollectionMemberIDs = OnyxUtils_1.default.getSkippableCollectionMemberIDs();
|
|
225
239
|
if (skippableCollectionMemberIDs.size) {
|
|
@@ -248,10 +262,10 @@ function multiSet(data) {
|
|
|
248
262
|
}
|
|
249
263
|
// Update cache and optimistically inform subscribers on the next tick
|
|
250
264
|
OnyxCache_1.default.set(key, value);
|
|
251
|
-
return OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, prevValue);
|
|
265
|
+
return OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, prevValue, undefined, isFromUpdate);
|
|
252
266
|
});
|
|
253
267
|
return storage_1.default.multiSet(keyValuePairsToSet)
|
|
254
|
-
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error,
|
|
268
|
+
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, multiSetInternal, newData, isFromUpdate))
|
|
255
269
|
.then(() => {
|
|
256
270
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MULTI_SET, undefined, newData);
|
|
257
271
|
return Promise.all(updatePromises);
|
|
@@ -275,6 +289,13 @@ function multiSet(data) {
|
|
|
275
289
|
* Onyx.merge(ONYXKEYS.POLICY, {name: 'My Workspace'}); // -> {id: 1, name: 'My Workspace'}
|
|
276
290
|
*/
|
|
277
291
|
function merge(key, changes) {
|
|
292
|
+
return mergeInternal(key, changes);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* @param isFromUpdate - Whether this call originates from Onyx.update()
|
|
296
|
+
* When isFromUpdate = true (called from Onyx.update()), useOnyx hook subscribers are batched to escape excessive re-renders in components
|
|
297
|
+
*/
|
|
298
|
+
function mergeInternal(key, changes, isFromUpdate = false) {
|
|
278
299
|
const skippableCollectionMemberIDs = OnyxUtils_1.default.getSkippableCollectionMemberIDs();
|
|
279
300
|
if (skippableCollectionMemberIDs.size) {
|
|
280
301
|
try {
|
|
@@ -329,7 +350,7 @@ function merge(key, changes) {
|
|
|
329
350
|
OnyxUtils_1.default.logKeyRemoved(OnyxUtils_1.default.METHOD.MERGE, key);
|
|
330
351
|
return Promise.resolve();
|
|
331
352
|
}
|
|
332
|
-
return OnyxMerge_1.default.applyMerge(key, existingValue, validChanges).then(({ mergedValue, updatePromise }) => {
|
|
353
|
+
return OnyxMerge_1.default.applyMerge(key, existingValue, validChanges, isFromUpdate).then(({ mergedValue, updatePromise }) => {
|
|
333
354
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MERGE, key, changes, mergedValue);
|
|
334
355
|
return updatePromise;
|
|
335
356
|
});
|
|
@@ -355,7 +376,14 @@ function merge(key, changes) {
|
|
|
355
376
|
* @param collection Object collection keyed by individual collection member keys and values
|
|
356
377
|
*/
|
|
357
378
|
function mergeCollection(collectionKey, collection) {
|
|
358
|
-
return
|
|
379
|
+
return mergeCollectionInternal(collectionKey, collection);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* @param isFromUpdate - Whether this call originates from Onyx.update()
|
|
383
|
+
* When isFromUpdate = true (called from Onyx.update()), useOnyx hook subscribers are batched to escape excessive re-renders in components
|
|
384
|
+
*/
|
|
385
|
+
function mergeCollectionInternal(collectionKey, collection, isFromUpdate = false) {
|
|
386
|
+
return OnyxUtils_1.default.mergeCollectionWithPatches(collectionKey, collection, undefined, isFromUpdate);
|
|
359
387
|
}
|
|
360
388
|
/**
|
|
361
389
|
* Clear out all the data in the store
|
|
@@ -435,10 +463,10 @@ function clear(keysToPreserve = []) {
|
|
|
435
463
|
const updatePromises = [];
|
|
436
464
|
// Notify the subscribers for each key/value group so they can receive the new values
|
|
437
465
|
Object.entries(keyValuesToResetIndividually).forEach(([key, value]) => {
|
|
438
|
-
updatePromises.push(OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, OnyxCache_1.default.get(key, false)));
|
|
466
|
+
updatePromises.push(OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, OnyxCache_1.default.get(key, false), undefined, false));
|
|
439
467
|
});
|
|
440
468
|
Object.entries(keyValuesToResetAsCollection).forEach(([key, value]) => {
|
|
441
|
-
updatePromises.push(OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(key, value));
|
|
469
|
+
updatePromises.push(OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(key, value, undefined, false));
|
|
442
470
|
});
|
|
443
471
|
const defaultKeyValuePairs = Object.entries(Object.keys(defaultKeyStates)
|
|
444
472
|
.filter((key) => !keysToPreserve.includes(key))
|
|
@@ -522,7 +550,7 @@ function update(data) {
|
|
|
522
550
|
collectionKeys.forEach((collectionKey) => enqueueMergeOperation(collectionKey, mergedCollection[collectionKey]));
|
|
523
551
|
}
|
|
524
552
|
},
|
|
525
|
-
[OnyxUtils_1.default.METHOD.SET_COLLECTION]: (k, v) => promises.push(() =>
|
|
553
|
+
[OnyxUtils_1.default.METHOD.SET_COLLECTION]: (k, v) => promises.push(() => setCollectionInternal(k, v, true)),
|
|
526
554
|
[OnyxUtils_1.default.METHOD.MULTI_SET]: (k, v) => Object.entries(v).forEach(([entryKey, entryValue]) => enqueueSetOperation(entryKey, entryValue)),
|
|
527
555
|
[OnyxUtils_1.default.METHOD.CLEAR]: () => {
|
|
528
556
|
clearPromise = clear();
|
|
@@ -564,23 +592,23 @@ function update(data) {
|
|
|
564
592
|
set: {},
|
|
565
593
|
});
|
|
566
594
|
if (!utils_1.default.isEmptyObject(batchedCollectionUpdates.merge)) {
|
|
567
|
-
promises.push(() => OnyxUtils_1.default.mergeCollectionWithPatches(collectionKey, batchedCollectionUpdates.merge, batchedCollectionUpdates.mergeReplaceNullPatches));
|
|
595
|
+
promises.push(() => OnyxUtils_1.default.mergeCollectionWithPatches(collectionKey, batchedCollectionUpdates.merge, batchedCollectionUpdates.mergeReplaceNullPatches, true));
|
|
568
596
|
}
|
|
569
597
|
if (!utils_1.default.isEmptyObject(batchedCollectionUpdates.set)) {
|
|
570
|
-
promises.push(() =>
|
|
598
|
+
promises.push(() => multiSetInternal(batchedCollectionUpdates.set, true));
|
|
571
599
|
}
|
|
572
600
|
});
|
|
573
601
|
Object.entries(updateQueue).forEach(([key, operations]) => {
|
|
574
602
|
if (operations[0] === null) {
|
|
575
603
|
const batchedChanges = OnyxUtils_1.default.mergeChanges(operations).result;
|
|
576
|
-
promises.push(() =>
|
|
604
|
+
promises.push(() => setInternal(key, batchedChanges, undefined, true));
|
|
577
605
|
return;
|
|
578
606
|
}
|
|
579
607
|
operations.forEach((operation) => {
|
|
580
|
-
promises.push(() =>
|
|
608
|
+
promises.push(() => mergeInternal(key, operation, true));
|
|
581
609
|
});
|
|
582
610
|
});
|
|
583
|
-
const snapshotPromises = OnyxUtils_1.default.updateSnapshots(data,
|
|
611
|
+
const snapshotPromises = OnyxUtils_1.default.updateSnapshots(data, (key, changes) => mergeInternal(key, changes, true));
|
|
584
612
|
// We need to run the snapshot updates before the other updates so the snapshot data can be updated before the loading state in the snapshot
|
|
585
613
|
const finalPromises = snapshotPromises.concat(promises);
|
|
586
614
|
return clearPromise.then(() => Promise.all(finalPromises.map((p) => p()))).then(() => undefined);
|
|
@@ -599,6 +627,13 @@ function update(data) {
|
|
|
599
627
|
* @param collection Object collection keyed by individual collection member keys and values
|
|
600
628
|
*/
|
|
601
629
|
function setCollection(collectionKey, collection) {
|
|
630
|
+
return setCollectionInternal(collectionKey, collection);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* @param isFromUpdate - Whether this call originates from Onyx.update()
|
|
634
|
+
* When isFromUpdate = true (called from Onyx.update()), useOnyx hook subscribers are batched to escape excessive re-renders in components
|
|
635
|
+
*/
|
|
636
|
+
function setCollectionInternal(collectionKey, collection, isFromUpdate = false) {
|
|
602
637
|
let resultCollection = collection;
|
|
603
638
|
let resultCollectionKeys = Object.keys(resultCollection);
|
|
604
639
|
// Confirm all the collection keys belong to the same parent
|
|
@@ -638,9 +673,9 @@ function setCollection(collectionKey, collection) {
|
|
|
638
673
|
const keyValuePairs = OnyxUtils_1.default.prepareKeyValuePairsForStorage(mutableCollection, true);
|
|
639
674
|
const previousCollection = OnyxUtils_1.default.getCachedCollection(collectionKey);
|
|
640
675
|
keyValuePairs.forEach(([key, value]) => OnyxCache_1.default.set(key, value));
|
|
641
|
-
const updatePromise = OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(collectionKey, mutableCollection, previousCollection);
|
|
676
|
+
const updatePromise = OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(collectionKey, mutableCollection, previousCollection, isFromUpdate);
|
|
642
677
|
return storage_1.default.multiSet(keyValuePairs)
|
|
643
|
-
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error,
|
|
678
|
+
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, setCollectionInternal, collectionKey, collection, isFromUpdate))
|
|
644
679
|
.then(() => {
|
|
645
680
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
646
681
|
return updatePromise;
|
package/dist/OnyxCache.d.ts
CHANGED
|
@@ -19,8 +19,8 @@ declare class OnyxCache {
|
|
|
19
19
|
private recentKeys;
|
|
20
20
|
/** A map of cached values */
|
|
21
21
|
private storageMap;
|
|
22
|
-
/**
|
|
23
|
-
private
|
|
22
|
+
/** Cache of complete collection data objects for O(1) retrieval */
|
|
23
|
+
private collectionData;
|
|
24
24
|
/**
|
|
25
25
|
* Captured pending tasks for already running storage methods
|
|
26
26
|
* Using a map yields better performance on operations such a delete
|
|
@@ -165,10 +165,6 @@ declare class OnyxCache {
|
|
|
165
165
|
* Get all data for a collection key
|
|
166
166
|
*/
|
|
167
167
|
getCollectionData(collectionKey: OnyxKey): Record<OnyxKey, OnyxValue<OnyxKey>> | undefined;
|
|
168
|
-
/**
|
|
169
|
-
* Get all member keys for a collection key
|
|
170
|
-
*/
|
|
171
|
-
getCollectionMemberKeys(collectionKey: OnyxKey): Set<OnyxKey> | undefined;
|
|
172
168
|
}
|
|
173
169
|
declare const instance: OnyxCache;
|
|
174
170
|
export default instance;
|
package/dist/OnyxCache.js
CHANGED
|
@@ -68,10 +68,10 @@ class OnyxCache {
|
|
|
68
68
|
this.nullishStorageKeys = new Set();
|
|
69
69
|
this.recentKeys = new Set();
|
|
70
70
|
this.storageMap = {};
|
|
71
|
-
this.
|
|
71
|
+
this.collectionData = {};
|
|
72
72
|
this.pendingPromises = new Map();
|
|
73
73
|
// bind all public methods to prevent problems with `this`
|
|
74
|
-
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'addToAccessedKeys', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys', 'setEvictionAllowList', 'getEvictionBlocklist', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'isCollectionKey', 'getCollectionKey', 'getCollectionData'
|
|
74
|
+
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'addToAccessedKeys', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys', 'setEvictionAllowList', 'getEvictionBlocklist', 'isEvictableKey', 'removeLastAccessedKey', 'addLastAccessedKey', 'addEvictableKeysToRecentlyAccessedList', 'getKeyForEviction', 'setCollectionKeys', 'isCollectionKey', 'getCollectionKey', 'getCollectionData');
|
|
75
75
|
}
|
|
76
76
|
/** Get all the storage keys */
|
|
77
77
|
getAllKeys() {
|
|
@@ -136,33 +136,33 @@ class OnyxCache {
|
|
|
136
136
|
const collectionKey = this.getCollectionKey(key);
|
|
137
137
|
if (value === null || value === undefined) {
|
|
138
138
|
delete this.storageMap[key];
|
|
139
|
-
// Remove from collection
|
|
140
|
-
if (collectionKey && this.
|
|
141
|
-
this.
|
|
139
|
+
// Remove from collection data cache if it's a collection member
|
|
140
|
+
if (collectionKey && this.collectionData[collectionKey]) {
|
|
141
|
+
delete this.collectionData[collectionKey][key];
|
|
142
142
|
}
|
|
143
143
|
return undefined;
|
|
144
144
|
}
|
|
145
145
|
this.storageMap[key] = value;
|
|
146
|
-
// Update collection
|
|
146
|
+
// Update collection data cache if this is a collection member
|
|
147
147
|
if (collectionKey) {
|
|
148
|
-
if (!this.
|
|
149
|
-
this.
|
|
148
|
+
if (!this.collectionData[collectionKey]) {
|
|
149
|
+
this.collectionData[collectionKey] = {};
|
|
150
150
|
}
|
|
151
|
-
this.
|
|
151
|
+
this.collectionData[collectionKey][key] = value;
|
|
152
152
|
}
|
|
153
153
|
return value;
|
|
154
154
|
}
|
|
155
155
|
/** Forget the cached value for the given key */
|
|
156
156
|
drop(key) {
|
|
157
157
|
delete this.storageMap[key];
|
|
158
|
-
//
|
|
158
|
+
// Remove from collection data cache if this is a collection member
|
|
159
159
|
const collectionKey = this.getCollectionKey(key);
|
|
160
|
-
if (collectionKey && this.
|
|
161
|
-
this.
|
|
160
|
+
if (collectionKey && this.collectionData[collectionKey]) {
|
|
161
|
+
delete this.collectionData[collectionKey][key];
|
|
162
162
|
}
|
|
163
|
-
// If this is a collection key, clear its
|
|
163
|
+
// If this is a collection key, clear its data
|
|
164
164
|
if (this.isCollectionKey(key)) {
|
|
165
|
-
delete this.
|
|
165
|
+
delete this.collectionData[key];
|
|
166
166
|
}
|
|
167
167
|
this.storageKeys.delete(key);
|
|
168
168
|
this.recentKeys.delete(key);
|
|
@@ -185,19 +185,19 @@ class OnyxCache {
|
|
|
185
185
|
const collectionKey = this.getCollectionKey(key);
|
|
186
186
|
if (value === null || value === undefined) {
|
|
187
187
|
this.addNullishStorageKey(key);
|
|
188
|
-
// Remove from collection
|
|
189
|
-
if (collectionKey && this.
|
|
190
|
-
this.
|
|
188
|
+
// Remove from collection data cache if it's a collection member
|
|
189
|
+
if (collectionKey && this.collectionData[collectionKey]) {
|
|
190
|
+
delete this.collectionData[collectionKey][key];
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
else {
|
|
194
194
|
this.nullishStorageKeys.delete(key);
|
|
195
|
-
// Update collection
|
|
195
|
+
// Update collection data cache if this is a collection member
|
|
196
196
|
if (collectionKey) {
|
|
197
|
-
if (!this.
|
|
198
|
-
this.
|
|
197
|
+
if (!this.collectionData[collectionKey]) {
|
|
198
|
+
this.collectionData[collectionKey] = {};
|
|
199
199
|
}
|
|
200
|
-
this.
|
|
200
|
+
this.collectionData[collectionKey][key] = this.storageMap[key];
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
});
|
|
@@ -257,10 +257,10 @@ class OnyxCache {
|
|
|
257
257
|
}
|
|
258
258
|
for (const key of keysToRemove) {
|
|
259
259
|
delete this.storageMap[key];
|
|
260
|
-
//
|
|
260
|
+
// Remove from collection data cache if this is a collection member
|
|
261
261
|
const collectionKey = this.getCollectionKey(key);
|
|
262
|
-
if (collectionKey && this.
|
|
263
|
-
this.
|
|
262
|
+
if (collectionKey && this.collectionData[collectionKey]) {
|
|
263
|
+
delete this.collectionData[collectionKey][key];
|
|
264
264
|
}
|
|
265
265
|
this.recentKeys.delete(key);
|
|
266
266
|
}
|
|
@@ -358,12 +358,12 @@ class OnyxCache {
|
|
|
358
358
|
*/
|
|
359
359
|
setCollectionKeys(collectionKeys) {
|
|
360
360
|
this.collectionKeys = collectionKeys;
|
|
361
|
-
// Initialize collection
|
|
361
|
+
// Initialize collection data for existing collection keys
|
|
362
362
|
collectionKeys.forEach((collectionKey) => {
|
|
363
|
-
if (this.
|
|
363
|
+
if (this.collectionData[collectionKey]) {
|
|
364
364
|
return;
|
|
365
365
|
}
|
|
366
|
-
this.
|
|
366
|
+
this.collectionData[collectionKey] = {};
|
|
367
367
|
});
|
|
368
368
|
}
|
|
369
369
|
/**
|
|
@@ -387,24 +387,12 @@ class OnyxCache {
|
|
|
387
387
|
* Get all data for a collection key
|
|
388
388
|
*/
|
|
389
389
|
getCollectionData(collectionKey) {
|
|
390
|
-
const
|
|
391
|
-
if (!
|
|
390
|
+
const cachedCollection = this.collectionData[collectionKey];
|
|
391
|
+
if (!cachedCollection || Object.keys(cachedCollection).length === 0) {
|
|
392
392
|
return undefined;
|
|
393
393
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const value = this.storageMap[memberKey];
|
|
397
|
-
if (value !== undefined) {
|
|
398
|
-
collectionData[memberKey] = value;
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
return collectionData;
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Get all member keys for a collection key
|
|
405
|
-
*/
|
|
406
|
-
getCollectionMemberKeys(collectionKey) {
|
|
407
|
-
return this.collectionIndex[collectionKey];
|
|
394
|
+
// Return a shallow copy to ensure React detects changes when items are added/removed
|
|
395
|
+
return Object.assign({}, cachedCollection);
|
|
408
396
|
}
|
|
409
397
|
}
|
|
410
398
|
const instance = new OnyxCache();
|
package/dist/OnyxMerge/index.js
CHANGED
|
@@ -6,14 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const OnyxCache_1 = __importDefault(require("../OnyxCache"));
|
|
7
7
|
const OnyxUtils_1 = __importDefault(require("../OnyxUtils"));
|
|
8
8
|
const storage_1 = __importDefault(require("../storage"));
|
|
9
|
-
const applyMerge = (key, existingValue, validChanges) => {
|
|
9
|
+
const applyMerge = (key, existingValue, validChanges, isFromUpdate = false) => {
|
|
10
10
|
const { result: mergedValue } = OnyxUtils_1.default.mergeChanges(validChanges, existingValue);
|
|
11
11
|
// In cache, we don't want to remove the key if it's null to improve performance and speed up the next merge.
|
|
12
12
|
const hasChanged = OnyxCache_1.default.hasValueChanged(key, mergedValue);
|
|
13
13
|
// Logging properties only since values could be sensitive things we don't want to log.
|
|
14
14
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.MERGE, key, mergedValue, hasChanged);
|
|
15
15
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
16
|
-
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
16
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged, isFromUpdate);
|
|
17
17
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
18
18
|
if (!hasChanged) {
|
|
19
19
|
return Promise.resolve({ mergedValue, updatePromise });
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const OnyxUtils_1 = __importDefault(require("../OnyxUtils"));
|
|
7
7
|
const OnyxCache_1 = __importDefault(require("../OnyxCache"));
|
|
8
8
|
const storage_1 = __importDefault(require("../storage"));
|
|
9
|
-
const applyMerge = (key, existingValue, validChanges) => {
|
|
9
|
+
const applyMerge = (key, existingValue, validChanges, isFromUpdate = false) => {
|
|
10
10
|
// If any of the changes is null, we need to discard the existing value.
|
|
11
11
|
const baseValue = validChanges.includes(null) ? undefined : existingValue;
|
|
12
12
|
// We first batch the changes into a single change with object removal marks,
|
|
@@ -19,7 +19,7 @@ const applyMerge = (key, existingValue, validChanges) => {
|
|
|
19
19
|
// Logging properties only since values could be sensitive things we don't want to log.
|
|
20
20
|
OnyxUtils_1.default.logKeyChanged(OnyxUtils_1.default.METHOD.MERGE, key, mergedValue, hasChanged);
|
|
21
21
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
22
|
-
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
22
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged, isFromUpdate);
|
|
23
23
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
24
24
|
if (!hasChanged) {
|
|
25
25
|
return Promise.resolve({ mergedValue, updatePromise });
|
|
@@ -3,5 +3,5 @@ type ApplyMergeResult<TValue> = {
|
|
|
3
3
|
mergedValue: TValue;
|
|
4
4
|
updatePromise: Promise<void>;
|
|
5
5
|
};
|
|
6
|
-
type ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<OnyxKey> | undefined, TChange extends OnyxInput<OnyxKey> | null>(key: TKey, existingValue: TValue, validChanges: TChange[]) => Promise<ApplyMergeResult<TChange>>;
|
|
6
|
+
type ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<OnyxKey> | undefined, TChange extends OnyxInput<OnyxKey> | null>(key: TKey, existingValue: TValue, validChanges: TChange[], isFromUpdate?: boolean) => Promise<ApplyMergeResult<TChange>>;
|
|
7
7
|
export type { ApplyMerge, ApplyMergeResult };
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -143,14 +143,14 @@ declare function getCachedCollection<TKey extends CollectionKeyBase>(collectionK
|
|
|
143
143
|
/**
|
|
144
144
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
145
145
|
*/
|
|
146
|
-
declare function keysChanged<TKey extends CollectionKeyBase>(collectionKey: TKey, partialCollection: OnyxCollection<KeyValueMapping[TKey]>, partialPreviousCollection: OnyxCollection<KeyValueMapping[TKey]> | undefined, notifyConnectSubscribers?: boolean, notifyWithOnyxSubscribers?: boolean): void;
|
|
146
|
+
declare function keysChanged<TKey extends CollectionKeyBase>(collectionKey: TKey, partialCollection: OnyxCollection<KeyValueMapping[TKey]>, partialPreviousCollection: OnyxCollection<KeyValueMapping[TKey]> | undefined, notifyConnectSubscribers?: boolean, notifyWithOnyxSubscribers?: boolean, notifyUseOnyxHookSubscribers?: boolean): void;
|
|
147
147
|
/**
|
|
148
148
|
* When a key change happens, search for any callbacks matching the key or collection key and trigger those callbacks
|
|
149
149
|
*
|
|
150
150
|
* @example
|
|
151
151
|
* keyChanged(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
152
152
|
*/
|
|
153
|
-
declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, previousValue: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: Mapping<OnyxKey>) => boolean, notifyConnectSubscribers?: boolean, notifyWithOnyxSubscribers?: boolean): void;
|
|
153
|
+
declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, previousValue: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: Mapping<OnyxKey>) => boolean, notifyConnectSubscribers?: boolean, notifyWithOnyxSubscribers?: boolean, notifyUseOnyxHookSubscribers?: boolean): void;
|
|
154
154
|
/**
|
|
155
155
|
* Sends the data obtained from the keys to the connection. It either:
|
|
156
156
|
* - sets state on the withOnyxInstances
|
|
@@ -172,13 +172,13 @@ declare function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matching
|
|
|
172
172
|
* @example
|
|
173
173
|
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
174
174
|
*/
|
|
175
|
-
declare function scheduleSubscriberUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, previousValue: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: Mapping<OnyxKey>) => boolean): Promise<void>;
|
|
175
|
+
declare function scheduleSubscriberUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, previousValue: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: Mapping<OnyxKey>) => boolean, isFromUpdate?: boolean): Promise<void>;
|
|
176
176
|
/**
|
|
177
177
|
* This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
|
|
178
178
|
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
179
179
|
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
180
180
|
*/
|
|
181
|
-
declare function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(key: TKey, value: OnyxCollection<KeyValueMapping[TKey]>, previousValue?: OnyxCollection<KeyValueMapping[TKey]
|
|
181
|
+
declare function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(key: TKey, value: OnyxCollection<KeyValueMapping[TKey]>, previousValue?: OnyxCollection<KeyValueMapping[TKey]>, isFromUpdate?: boolean): Promise<void>;
|
|
182
182
|
/**
|
|
183
183
|
* Remove a key from Onyx and update the subscribers
|
|
184
184
|
*/
|
|
@@ -193,7 +193,7 @@ declare function evictStorageAndRetry<TMethod extends typeof Onyx.set | typeof O
|
|
|
193
193
|
/**
|
|
194
194
|
* Notifies subscribers and writes current value to cache
|
|
195
195
|
*/
|
|
196
|
-
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean): Promise<void>;
|
|
196
|
+
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean, isFromUpdate?: boolean): Promise<void>;
|
|
197
197
|
declare function hasPendingMergeForKey(key: OnyxKey): boolean;
|
|
198
198
|
/**
|
|
199
199
|
* Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
|
|
@@ -254,7 +254,7 @@ declare function updateSnapshots(data: OnyxUpdate[], mergeFn: typeof Onyx.merge)
|
|
|
254
254
|
* @param mergeReplaceNullPatches Record where the key is a collection member key and the value is a list of
|
|
255
255
|
* tuples that we'll use to replace the nested objects of that collection member record with something else.
|
|
256
256
|
*/
|
|
257
|
-
declare function mergeCollectionWithPatches<TKey extends CollectionKeyBase, TMap>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TKey, TMap>, mergeReplaceNullPatches?: MultiMergeReplaceNullPatches): Promise<void>;
|
|
257
|
+
declare function mergeCollectionWithPatches<TKey extends CollectionKeyBase, TMap>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TKey, TMap>, mergeReplaceNullPatches?: MultiMergeReplaceNullPatches, isFromUpdate?: boolean): Promise<void>;
|
|
258
258
|
declare function logKeyChanged(onyxMethod: Extract<OnyxMethod, 'set' | 'merge'>, key: OnyxKey, value: unknown, hasChanged: boolean): void;
|
|
259
259
|
declare function logKeyRemoved(onyxMethod: Extract<OnyxMethod, 'set' | 'merge'>, key: OnyxKey): void;
|
|
260
260
|
/**
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -440,25 +440,16 @@ function tryGetCachedValue(key, mapping) {
|
|
|
440
440
|
let val = OnyxCache_1.default.get(key);
|
|
441
441
|
if (isCollectionKey(key)) {
|
|
442
442
|
const collectionData = OnyxCache_1.default.getCollectionData(key);
|
|
443
|
-
|
|
444
|
-
if (collectionData !== undefined && allCacheKeys.size > 0) {
|
|
443
|
+
if (collectionData !== undefined) {
|
|
445
444
|
val = collectionData;
|
|
446
445
|
}
|
|
447
446
|
else {
|
|
448
|
-
//
|
|
449
|
-
|
|
450
|
-
// collection actually exists.
|
|
451
|
-
if (allCacheKeys.size === 0) {
|
|
447
|
+
// If we haven't loaded all keys yet, we can't determine if the collection exists
|
|
448
|
+
if (OnyxCache_1.default.getAllKeys().size === 0) {
|
|
452
449
|
return;
|
|
453
450
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
if (!cacheKey.startsWith(key)) {
|
|
457
|
-
return;
|
|
458
|
-
}
|
|
459
|
-
values[cacheKey] = OnyxCache_1.default.get(cacheKey);
|
|
460
|
-
});
|
|
461
|
-
val = values;
|
|
451
|
+
// Set an empty collection object for collections that exist but have no data
|
|
452
|
+
val = {};
|
|
462
453
|
}
|
|
463
454
|
}
|
|
464
455
|
if (mapping === null || mapping === void 0 ? void 0 : mapping.selector) {
|
|
@@ -512,7 +503,7 @@ function getCachedCollection(collectionKey, collectionMemberKeys) {
|
|
|
512
503
|
/**
|
|
513
504
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
514
505
|
*/
|
|
515
|
-
function keysChanged(collectionKey, partialCollection, partialPreviousCollection, notifyConnectSubscribers = true, notifyWithOnyxSubscribers = true) {
|
|
506
|
+
function keysChanged(collectionKey, partialCollection, partialPreviousCollection, notifyConnectSubscribers = true, notifyWithOnyxSubscribers = true, notifyUseOnyxHookSubscribers = true) {
|
|
516
507
|
// We prepare the "cached collection" which is the entire collection + the new partial data that
|
|
517
508
|
// was merged in via mergeCollection().
|
|
518
509
|
const cachedCollection = getCachedCollection(collectionKey);
|
|
@@ -540,7 +531,8 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
540
531
|
const isSubscribedToCollectionMemberKey = isCollectionMemberKey(collectionKey, subscriber.key);
|
|
541
532
|
// Regular Onyx.connect() subscriber found.
|
|
542
533
|
if (typeof subscriber.callback === 'function') {
|
|
543
|
-
if (
|
|
534
|
+
// Check if it's a useOnyx or a regular Onyx.connect() subscriber
|
|
535
|
+
if ((subscriber.isUseOnyxSubscriber && !notifyUseOnyxHookSubscribers) || (!subscriber.isUseOnyxSubscriber && !notifyConnectSubscribers)) {
|
|
544
536
|
continue;
|
|
545
537
|
}
|
|
546
538
|
// If they are subscribed to the collection key and using waitForCollectionCallback then we'll
|
|
@@ -670,7 +662,7 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
670
662
|
* @example
|
|
671
663
|
* keyChanged(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
672
664
|
*/
|
|
673
|
-
function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true, notifyConnectSubscribers = true, notifyWithOnyxSubscribers = true) {
|
|
665
|
+
function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true, notifyConnectSubscribers = true, notifyWithOnyxSubscribers = true, notifyUseOnyxHookSubscribers = true) {
|
|
674
666
|
var _a, _b;
|
|
675
667
|
// Add or remove this key from the recentlyAccessedKeys lists
|
|
676
668
|
if (value !== null) {
|
|
@@ -709,7 +701,8 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
709
701
|
}
|
|
710
702
|
// Subscriber is a regular call to connect() and provided a callback
|
|
711
703
|
if (typeof subscriber.callback === 'function') {
|
|
712
|
-
if (
|
|
704
|
+
// Check if it's a useOnyx or a regular Onyx.connect() subscriber
|
|
705
|
+
if ((subscriber.isUseOnyxSubscriber && !notifyUseOnyxHookSubscribers) || (!subscriber.isUseOnyxSubscriber && !notifyConnectSubscribers)) {
|
|
713
706
|
continue;
|
|
714
707
|
}
|
|
715
708
|
if (lastConnectionCallbackData.has(subscriber.subscriptionID) && lastConnectionCallbackData.get(subscriber.subscriptionID) === value) {
|
|
@@ -888,9 +881,9 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
888
881
|
* @example
|
|
889
882
|
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
890
883
|
*/
|
|
891
|
-
function scheduleSubscriberUpdate(key, value, previousValue, canUpdateSubscriber = () => true) {
|
|
892
|
-
const promise = Promise.resolve().then(() => keyChanged(key, value, previousValue, canUpdateSubscriber, true, false));
|
|
893
|
-
batchUpdates(() => keyChanged(key, value, previousValue, canUpdateSubscriber, false, true));
|
|
884
|
+
function scheduleSubscriberUpdate(key, value, previousValue, canUpdateSubscriber = () => true, isFromUpdate = false) {
|
|
885
|
+
const promise = Promise.resolve().then(() => keyChanged(key, value, previousValue, canUpdateSubscriber, true, false, !isFromUpdate));
|
|
886
|
+
batchUpdates(() => keyChanged(key, value, previousValue, canUpdateSubscriber, false, true, isFromUpdate));
|
|
894
887
|
return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
|
|
895
888
|
}
|
|
896
889
|
/**
|
|
@@ -898,9 +891,9 @@ function scheduleSubscriberUpdate(key, value, previousValue, canUpdateSubscriber
|
|
|
898
891
|
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
899
892
|
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
900
893
|
*/
|
|
901
|
-
function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
902
|
-
const promise = Promise.resolve().then(() => keysChanged(key, value, previousValue, true, false));
|
|
903
|
-
batchUpdates(() => keysChanged(key, value, previousValue, false, true));
|
|
894
|
+
function scheduleNotifyCollectionSubscribers(key, value, previousValue, isFromUpdate = false) {
|
|
895
|
+
const promise = Promise.resolve().then(() => keysChanged(key, value, previousValue, true, false, !isFromUpdate));
|
|
896
|
+
batchUpdates(() => keysChanged(key, value, previousValue, false, true, isFromUpdate));
|
|
904
897
|
return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
|
|
905
898
|
}
|
|
906
899
|
/**
|
|
@@ -950,7 +943,7 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
950
943
|
/**
|
|
951
944
|
* Notifies subscribers and writes current value to cache
|
|
952
945
|
*/
|
|
953
|
-
function broadcastUpdate(key, value, hasChanged) {
|
|
946
|
+
function broadcastUpdate(key, value, hasChanged, isFromUpdate = false) {
|
|
954
947
|
const prevValue = OnyxCache_1.default.get(key, false);
|
|
955
948
|
// Update subscribers if the cached value has changed, or when the subscriber specifically requires
|
|
956
949
|
// all updates regardless of value changes (indicated by initWithStoredValues set to false).
|
|
@@ -960,7 +953,7 @@ function broadcastUpdate(key, value, hasChanged) {
|
|
|
960
953
|
else {
|
|
961
954
|
OnyxCache_1.default.addToAccessedKeys(key);
|
|
962
955
|
}
|
|
963
|
-
return scheduleSubscriberUpdate(key, value, prevValue, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false).then(() => undefined);
|
|
956
|
+
return scheduleSubscriberUpdate(key, value, prevValue, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false, isFromUpdate).then(() => undefined);
|
|
964
957
|
}
|
|
965
958
|
function hasPendingMergeForKey(key) {
|
|
966
959
|
return !!mergeQueue[key];
|
|
@@ -1238,7 +1231,7 @@ function updateSnapshots(data, mergeFn) {
|
|
|
1238
1231
|
* @param mergeReplaceNullPatches Record where the key is a collection member key and the value is a list of
|
|
1239
1232
|
* tuples that we'll use to replace the nested objects of that collection member record with something else.
|
|
1240
1233
|
*/
|
|
1241
|
-
function mergeCollectionWithPatches(collectionKey, collection, mergeReplaceNullPatches) {
|
|
1234
|
+
function mergeCollectionWithPatches(collectionKey, collection, mergeReplaceNullPatches, isFromUpdate = false) {
|
|
1242
1235
|
if (!isValidNonEmptyCollectionForMerge(collection)) {
|
|
1243
1236
|
Logger.logInfo('mergeCollection() called with invalid or empty value. Skipping this update.');
|
|
1244
1237
|
return Promise.resolve();
|
|
@@ -1320,7 +1313,7 @@ function mergeCollectionWithPatches(collectionKey, collection, mergeReplaceNullP
|
|
|
1320
1313
|
// and update all subscribers
|
|
1321
1314
|
const promiseUpdate = previousCollectionPromise.then((previousCollection) => {
|
|
1322
1315
|
OnyxCache_1.default.merge(finalMergedCollection);
|
|
1323
|
-
return scheduleNotifyCollectionSubscribers(collectionKey, finalMergedCollection, previousCollection);
|
|
1316
|
+
return scheduleNotifyCollectionSubscribers(collectionKey, finalMergedCollection, previousCollection, isFromUpdate);
|
|
1324
1317
|
});
|
|
1325
1318
|
return Promise.all(promises)
|
|
1326
1319
|
.catch((error) => evictStorageAndRetry(error, mergeCollectionWithPatches, collectionKey, resultCollection))
|
package/dist/types.d.ts
CHANGED
|
@@ -235,6 +235,8 @@ type BaseConnectOptions = {
|
|
|
235
235
|
* with the same connect configurations.
|
|
236
236
|
*/
|
|
237
237
|
reuseConnection?: boolean;
|
|
238
|
+
/** Indicates whether this subscriber is created from the useOnyx hook. */
|
|
239
|
+
isUseOnyxSubscriber?: boolean;
|
|
238
240
|
};
|
|
239
241
|
/** Represents the callback function used in `Onyx.connect()` method with a regular key. */
|
|
240
242
|
type DefaultConnectCallback<TKey extends OnyxKey> = (value: OnyxEntry<KeyValueMapping[TKey]>, key: TKey) => void;
|
package/dist/useOnyx.js
CHANGED
|
@@ -276,6 +276,7 @@ function useOnyx(key, options, dependencies = []) {
|
|
|
276
276
|
initWithStoredValues: options === null || options === void 0 ? void 0 : options.initWithStoredValues,
|
|
277
277
|
waitForCollectionCallback: OnyxUtils_1.default.isCollectionKey(key),
|
|
278
278
|
reuseConnection: options === null || options === void 0 ? void 0 : options.reuseConnection,
|
|
279
|
+
isUseOnyxSubscriber: true,
|
|
279
280
|
});
|
|
280
281
|
checkEvictableKey();
|
|
281
282
|
return () => {
|