react-native-onyx 3.0.49 → 3.0.50
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 +11 -8
- package/dist/OnyxMerge/index.js +3 -2
- package/dist/OnyxMerge/index.native.js +3 -2
- package/dist/OnyxMerge/types.d.ts +1 -0
- package/dist/OnyxUtils.d.ts +17 -2
- package/dist/OnyxUtils.js +74 -39
- package/package.json +1 -1
package/dist/Onyx.js
CHANGED
|
@@ -246,8 +246,9 @@ function merge(key, changes) {
|
|
|
246
246
|
OnyxUtils_1.default.logKeyRemoved(OnyxUtils_1.default.METHOD.MERGE, key);
|
|
247
247
|
return Promise.resolve();
|
|
248
248
|
}
|
|
249
|
-
return OnyxMerge_1.default.applyMerge(key, existingValue, validChanges).then(({ mergedValue }) => {
|
|
249
|
+
return OnyxMerge_1.default.applyMerge(key, existingValue, validChanges).then(({ mergedValue, updatePromise }) => {
|
|
250
250
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MERGE, key, changes, mergedValue);
|
|
251
|
+
return updatePromise;
|
|
251
252
|
});
|
|
252
253
|
}
|
|
253
254
|
catch (error) {
|
|
@@ -346,6 +347,14 @@ function clear(keysToPreserve = []) {
|
|
|
346
347
|
// If it isn't preserved and doesn't have a default, we'll remove it
|
|
347
348
|
keysToBeClearedFromStorage.push(key);
|
|
348
349
|
}
|
|
350
|
+
const updatePromises = [];
|
|
351
|
+
// Notify the subscribers for each key/value group so they can receive the new values
|
|
352
|
+
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
|
|
353
|
+
updatePromises.push(OnyxUtils_1.default.scheduleSubscriberUpdate(key, value));
|
|
354
|
+
}
|
|
355
|
+
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
|
|
356
|
+
updatePromises.push(OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(key, value.newValues, value.oldValues));
|
|
357
|
+
}
|
|
349
358
|
// Exclude RAM-only keys to prevent them from being saved to storage
|
|
350
359
|
const defaultKeyValuePairs = Object.entries(Object.keys(defaultKeyStates)
|
|
351
360
|
.filter((key) => !keysToPreserve.includes(key) && !OnyxUtils_1.default.isRamOnlyKey(key))
|
|
@@ -362,13 +371,7 @@ function clear(keysToPreserve = []) {
|
|
|
362
371
|
.then(() => storage_1.default.multiSet(defaultKeyValuePairs))
|
|
363
372
|
.then(() => {
|
|
364
373
|
DevTools_1.default.clearState(keysToPreserve);
|
|
365
|
-
|
|
366
|
-
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
|
|
367
|
-
OnyxUtils_1.default.keyChanged(key, value);
|
|
368
|
-
}
|
|
369
|
-
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
|
|
370
|
-
OnyxUtils_1.default.keysChanged(key, value.newValues, value.oldValues);
|
|
371
|
-
}
|
|
374
|
+
return Promise.all(updatePromises);
|
|
372
375
|
});
|
|
373
376
|
})
|
|
374
377
|
.then(() => undefined);
|
package/dist/OnyxMerge/index.js
CHANGED
|
@@ -13,16 +13,17 @@ const applyMerge = (key, existingValue, validChanges) => {
|
|
|
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
|
-
OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
16
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
17
17
|
const shouldSkipStorageOperations = !hasChanged || OnyxUtils_1.default.isRamOnlyKey(key);
|
|
18
18
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
19
19
|
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
|
|
20
20
|
if (shouldSkipStorageOperations) {
|
|
21
|
-
return Promise.resolve({ mergedValue });
|
|
21
|
+
return Promise.resolve({ mergedValue, updatePromise });
|
|
22
22
|
}
|
|
23
23
|
// For web platforms we use `setItem` since the object was already merged with its changes before.
|
|
24
24
|
return storage_1.default.setItem(key, mergedValue).then(() => ({
|
|
25
25
|
mergedValue,
|
|
26
|
+
updatePromise,
|
|
26
27
|
}));
|
|
27
28
|
};
|
|
28
29
|
const OnyxMerge = {
|
|
@@ -19,17 +19,18 @@ 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
|
-
OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
22
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, mergedValue, hasChanged);
|
|
23
23
|
const shouldSkipStorageOperations = !hasChanged || OnyxUtils_1.default.isRamOnlyKey(key);
|
|
24
24
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
25
25
|
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
|
|
26
26
|
if (shouldSkipStorageOperations) {
|
|
27
|
-
return Promise.resolve({ mergedValue });
|
|
27
|
+
return Promise.resolve({ mergedValue, updatePromise });
|
|
28
28
|
}
|
|
29
29
|
// For native platforms we use `mergeItem` that will take advantage of JSON_PATCH and JSON_REPLACE SQL operations to
|
|
30
30
|
// merge the object in a performant way.
|
|
31
31
|
return storage_1.default.mergeItem(key, batchedChanges, replaceNullPatches).then(() => ({
|
|
32
32
|
mergedValue,
|
|
33
|
+
updatePromise,
|
|
33
34
|
}));
|
|
34
35
|
};
|
|
35
36
|
const OnyxMerge = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { OnyxInput, OnyxKey } from '../types';
|
|
2
2
|
type ApplyMergeResult<TValue> = {
|
|
3
3
|
mergedValue: TValue;
|
|
4
|
+
updatePromise: Promise<void>;
|
|
4
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
7
|
export type { ApplyMerge, ApplyMergeResult };
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -186,7 +186,7 @@ declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TK
|
|
|
186
186
|
/**
|
|
187
187
|
* Sends the data obtained from the keys to the connection.
|
|
188
188
|
*/
|
|
189
|
-
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: CallbackToStateMapping<TKey>, matchedKey: TKey | undefined): void;
|
|
189
|
+
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: CallbackToStateMapping<TKey>, value: OnyxValue<TKey> | null, matchedKey: TKey | undefined): void;
|
|
190
190
|
/**
|
|
191
191
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
192
192
|
* run out of storage the least recently accessed key can be removed.
|
|
@@ -196,6 +196,19 @@ declare function addKeyToRecentlyAccessedIfNeeded<TKey extends OnyxKey>(key: TKe
|
|
|
196
196
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
197
197
|
*/
|
|
198
198
|
declare function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matchingKeys: CollectionKeyBase[], mapping: CallbackToStateMapping<TKey>): void;
|
|
199
|
+
/**
|
|
200
|
+
* Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
204
|
+
*/
|
|
205
|
+
declare function scheduleSubscriberUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: CallbackToStateMapping<OnyxKey>) => boolean, isProcessingCollectionUpdate?: boolean): Promise<void>;
|
|
206
|
+
/**
|
|
207
|
+
* This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
|
|
208
|
+
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
209
|
+
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
210
|
+
*/
|
|
211
|
+
declare function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(key: TKey, value: OnyxCollection<KeyValueMapping[TKey]>, previousValue?: OnyxCollection<KeyValueMapping[TKey]>): Promise<void>;
|
|
199
212
|
/**
|
|
200
213
|
* Remove a key from Onyx and update the subscribers
|
|
201
214
|
*/
|
|
@@ -211,7 +224,7 @@ declare function retryOperation<TMethod extends RetriableOnyxOperation>(error: E
|
|
|
211
224
|
/**
|
|
212
225
|
* Notifies subscribers and writes current value to cache
|
|
213
226
|
*/
|
|
214
|
-
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean): void
|
|
227
|
+
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean): Promise<void>;
|
|
215
228
|
declare function hasPendingMergeForKey(key: OnyxKey): boolean;
|
|
216
229
|
/**
|
|
217
230
|
* Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
|
|
@@ -357,6 +370,8 @@ declare const OnyxUtils: {
|
|
|
357
370
|
sendDataToConnection: typeof sendDataToConnection;
|
|
358
371
|
getCollectionKey: typeof getCollectionKey;
|
|
359
372
|
getCollectionDataAndSendAsObject: typeof getCollectionDataAndSendAsObject;
|
|
373
|
+
scheduleSubscriberUpdate: typeof scheduleSubscriberUpdate;
|
|
374
|
+
scheduleNotifyCollectionSubscribers: typeof scheduleNotifyCollectionSubscribers;
|
|
360
375
|
remove: typeof remove;
|
|
361
376
|
reportStorageQuota: typeof reportStorageQuota;
|
|
362
377
|
retryOperation: typeof retryOperation;
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -74,6 +74,8 @@ const MAX_STORAGE_OPERATION_RETRY_ATTEMPTS = 5;
|
|
|
74
74
|
// Key/value store of Onyx key and arrays of values to merge
|
|
75
75
|
let mergeQueue = {};
|
|
76
76
|
let mergeQueuePromise = {};
|
|
77
|
+
// Used to schedule subscriber update to the macro task queue
|
|
78
|
+
let nextMacrotaskPromise = null;
|
|
77
79
|
// Holds a mapping of all the React components that want their state subscribed to a store key
|
|
78
80
|
let callbackToStateMapping = {};
|
|
79
81
|
// Keeps a copy of the values of the onyx collection keys as a map for faster lookups
|
|
@@ -584,7 +586,6 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
584
586
|
// If they are subscribed to the collection key and using waitForCollectionCallback then we'll
|
|
585
587
|
// send the whole cached collection.
|
|
586
588
|
if (isSubscribedToCollectionKey) {
|
|
587
|
-
lastConnectionCallbackData.set(subscriber.subscriptionID, cachedCollection);
|
|
588
589
|
if (subscriber.waitForCollectionCallback) {
|
|
589
590
|
subscriber.callback(cachedCollection, subscriber.key, partialCollection);
|
|
590
591
|
continue;
|
|
@@ -667,7 +668,6 @@ function keyChanged(key, value, canUpdateSubscriber = () => true, isProcessingCo
|
|
|
667
668
|
cachedCollections[subscriber.key] = cachedCollection;
|
|
668
669
|
}
|
|
669
670
|
cachedCollection[key] = value;
|
|
670
|
-
lastConnectionCallbackData.set(subscriber.subscriptionID, cachedCollection);
|
|
671
671
|
subscriber.callback(cachedCollection, subscriber.key, { [key]: value });
|
|
672
672
|
continue;
|
|
673
673
|
}
|
|
@@ -682,32 +682,22 @@ function keyChanged(key, value, canUpdateSubscriber = () => true, isProcessingCo
|
|
|
682
682
|
/**
|
|
683
683
|
* Sends the data obtained from the keys to the connection.
|
|
684
684
|
*/
|
|
685
|
-
function sendDataToConnection(mapping, matchedKey) {
|
|
685
|
+
function sendDataToConnection(mapping, value, matchedKey) {
|
|
686
686
|
var _a, _b;
|
|
687
687
|
// If the mapping no longer exists then we should not send any data.
|
|
688
688
|
// This means our subscriber was disconnected.
|
|
689
689
|
if (!callbackToStateMapping[mapping.subscriptionID]) {
|
|
690
690
|
return;
|
|
691
691
|
}
|
|
692
|
-
// Always read the latest value from cache to avoid stale or duplicate data.
|
|
693
|
-
// For collection subscribers with waitForCollectionCallback, read the full collection.
|
|
694
|
-
// For individual key subscribers, read just that key's value.
|
|
695
|
-
let value;
|
|
696
|
-
if (isCollectionKey(mapping.key) && mapping.waitForCollectionCallback) {
|
|
697
|
-
const collection = getCachedCollection(mapping.key);
|
|
698
|
-
value = Object.keys(collection).length > 0 ? collection : undefined;
|
|
699
|
-
}
|
|
700
|
-
else {
|
|
701
|
-
value = OnyxCache_1.default.get(matchedKey !== null && matchedKey !== void 0 ? matchedKey : mapping.key);
|
|
702
|
-
}
|
|
703
692
|
// For regular callbacks, we never want to pass null values, but always just undefined if a value is not set in cache or storage.
|
|
704
|
-
|
|
693
|
+
const valueToPass = value === null ? undefined : value;
|
|
705
694
|
const lastValue = lastConnectionCallbackData.get(mapping.subscriptionID);
|
|
695
|
+
lastConnectionCallbackData.get(mapping.subscriptionID);
|
|
706
696
|
// If the value has not changed we do not need to trigger the callback
|
|
707
|
-
if (lastConnectionCallbackData.has(mapping.subscriptionID) &&
|
|
697
|
+
if (lastConnectionCallbackData.has(mapping.subscriptionID) && valueToPass === lastValue) {
|
|
708
698
|
return;
|
|
709
699
|
}
|
|
710
|
-
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a,
|
|
700
|
+
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, valueToPass, matchedKey);
|
|
711
701
|
}
|
|
712
702
|
/**
|
|
713
703
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
@@ -726,16 +716,50 @@ function addKeyToRecentlyAccessedIfNeeded(key) {
|
|
|
726
716
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
727
717
|
*/
|
|
728
718
|
function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
729
|
-
multiGet(matchingKeys).then(() => {
|
|
730
|
-
|
|
719
|
+
multiGet(matchingKeys).then((dataMap) => {
|
|
720
|
+
const data = Object.fromEntries(dataMap.entries());
|
|
721
|
+
sendDataToConnection(mapping, data, mapping.key);
|
|
731
722
|
});
|
|
732
723
|
}
|
|
724
|
+
/**
|
|
725
|
+
* Delays promise resolution until the next macrotask to prevent race condition if the key subscription is in progress.
|
|
726
|
+
*
|
|
727
|
+
* @param callback The keyChanged/keysChanged callback
|
|
728
|
+
* */
|
|
729
|
+
function prepareSubscriberUpdate(callback) {
|
|
730
|
+
if (!nextMacrotaskPromise) {
|
|
731
|
+
nextMacrotaskPromise = new Promise((resolve) => {
|
|
732
|
+
setTimeout(() => {
|
|
733
|
+
nextMacrotaskPromise = null;
|
|
734
|
+
resolve();
|
|
735
|
+
}, 0);
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
return Promise.all([nextMacrotaskPromise, Promise.resolve().then(callback)]).then();
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
|
|
742
|
+
*
|
|
743
|
+
* @example
|
|
744
|
+
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
745
|
+
*/
|
|
746
|
+
function scheduleSubscriberUpdate(key, value, canUpdateSubscriber = () => true, isProcessingCollectionUpdate = false) {
|
|
747
|
+
return prepareSubscriberUpdate(() => keyChanged(key, value, canUpdateSubscriber, isProcessingCollectionUpdate));
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
|
|
751
|
+
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
752
|
+
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
753
|
+
*/
|
|
754
|
+
function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
755
|
+
return prepareSubscriberUpdate(() => keysChanged(key, value, previousValue));
|
|
756
|
+
}
|
|
733
757
|
/**
|
|
734
758
|
* Remove a key from Onyx and update the subscribers
|
|
735
759
|
*/
|
|
736
760
|
function remove(key, isProcessingCollectionUpdate) {
|
|
737
761
|
OnyxCache_1.default.drop(key);
|
|
738
|
-
|
|
762
|
+
scheduleSubscriberUpdate(key, undefined, undefined, isProcessingCollectionUpdate);
|
|
739
763
|
if (isRamOnlyKey(key)) {
|
|
740
764
|
return Promise.resolve();
|
|
741
765
|
}
|
|
@@ -803,7 +827,7 @@ function broadcastUpdate(key, value, hasChanged) {
|
|
|
803
827
|
else {
|
|
804
828
|
OnyxCache_1.default.addToAccessedKeys(key);
|
|
805
829
|
}
|
|
806
|
-
|
|
830
|
+
return scheduleSubscriberUpdate(key, value, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false).then(() => undefined);
|
|
807
831
|
}
|
|
808
832
|
function hasPendingMergeForKey(key) {
|
|
809
833
|
return !!mergeQueue[key];
|
|
@@ -978,7 +1002,7 @@ function subscribeToKey(connectOptions) {
|
|
|
978
1002
|
const matchedKey = isCollectionKey(mapping.key) && mapping.waitForCollectionCallback ? mapping.key : undefined;
|
|
979
1003
|
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
|
|
980
1004
|
// or they will be undefined.
|
|
981
|
-
sendDataToConnection(mapping, matchedKey);
|
|
1005
|
+
sendDataToConnection(mapping, null, matchedKey);
|
|
982
1006
|
return;
|
|
983
1007
|
}
|
|
984
1008
|
// When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
|
|
@@ -991,15 +1015,15 @@ function subscribeToKey(connectOptions) {
|
|
|
991
1015
|
return;
|
|
992
1016
|
}
|
|
993
1017
|
// We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
|
|
994
|
-
multiGet(matchingKeys).then(() => {
|
|
995
|
-
for (const key of
|
|
996
|
-
sendDataToConnection(mapping, key);
|
|
1018
|
+
multiGet(matchingKeys).then((values) => {
|
|
1019
|
+
for (const [key, val] of values.entries()) {
|
|
1020
|
+
sendDataToConnection(mapping, val, key);
|
|
997
1021
|
}
|
|
998
1022
|
});
|
|
999
1023
|
return;
|
|
1000
1024
|
}
|
|
1001
1025
|
// If we are not subscribed to a collection key then there's only a single key to send an update for.
|
|
1002
|
-
get(mapping.key).then(() => sendDataToConnection(mapping, mapping.key));
|
|
1026
|
+
get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key));
|
|
1003
1027
|
return;
|
|
1004
1028
|
}
|
|
1005
1029
|
console.error('Warning: Onyx.connect() was found without a callback');
|
|
@@ -1133,20 +1157,21 @@ function setWithRetry({ key, value, options }, retryAttempt) {
|
|
|
1133
1157
|
const hasChanged = (options === null || options === void 0 ? void 0 : options.skipCacheCheck) ? true : OnyxCache_1.default.hasValueChanged(key, valueWithoutNestedNullValues);
|
|
1134
1158
|
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.SET, key, value, hasChanged);
|
|
1135
1159
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
1136
|
-
OnyxUtils.broadcastUpdate(key, valueWithoutNestedNullValues, hasChanged);
|
|
1160
|
+
const updatePromise = OnyxUtils.broadcastUpdate(key, valueWithoutNestedNullValues, hasChanged);
|
|
1137
1161
|
// If the value has not changed and this isn't a retry attempt, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
1138
1162
|
if (!hasChanged && !retryAttempt) {
|
|
1139
|
-
return
|
|
1163
|
+
return updatePromise;
|
|
1140
1164
|
}
|
|
1141
1165
|
// If a key is a RAM-only key or a member of RAM-only collection, we skip the step that modifies the storage
|
|
1142
1166
|
if (isRamOnlyKey(key)) {
|
|
1143
1167
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET, key, valueWithoutNestedNullValues);
|
|
1144
|
-
return
|
|
1168
|
+
return updatePromise;
|
|
1145
1169
|
}
|
|
1146
1170
|
return storage_1.default.setItem(key, valueWithoutNestedNullValues)
|
|
1147
1171
|
.catch((error) => OnyxUtils.retryOperation(error, setWithRetry, { key, value: valueWithoutNestedNullValues, options }, retryAttempt))
|
|
1148
1172
|
.then(() => {
|
|
1149
1173
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET, key, valueWithoutNestedNullValues);
|
|
1174
|
+
return updatePromise;
|
|
1150
1175
|
});
|
|
1151
1176
|
}
|
|
1152
1177
|
/**
|
|
@@ -1176,16 +1201,16 @@ function multiSetWithRetry(data, retryAttempt) {
|
|
|
1176
1201
|
}, {});
|
|
1177
1202
|
}
|
|
1178
1203
|
const keyValuePairsToSet = OnyxUtils.prepareKeyValuePairsForStorage(newData, true);
|
|
1179
|
-
|
|
1204
|
+
const updatePromises = keyValuePairsToSet.map(([key, value]) => {
|
|
1180
1205
|
// When we use multiSet to set a key we want to clear the current delta changes from Onyx.merge that were queued
|
|
1181
1206
|
// before the value was set. If Onyx.merge is currently reading the old value from storage, it will then not apply the changes.
|
|
1182
1207
|
if (OnyxUtils.hasPendingMergeForKey(key)) {
|
|
1183
1208
|
delete OnyxUtils.getMergeQueue()[key];
|
|
1184
1209
|
}
|
|
1185
|
-
// Update cache and optimistically inform subscribers
|
|
1210
|
+
// Update cache and optimistically inform subscribers on the next tick
|
|
1186
1211
|
OnyxCache_1.default.set(key, value);
|
|
1187
|
-
|
|
1188
|
-
}
|
|
1212
|
+
return OnyxUtils.scheduleSubscriberUpdate(key, value);
|
|
1213
|
+
});
|
|
1189
1214
|
const keyValuePairsToStore = keyValuePairsToSet.filter((keyValuePair) => {
|
|
1190
1215
|
const [key] = keyValuePair;
|
|
1191
1216
|
// Filter out the RAM-only key value pairs, as they should not be saved to storage
|
|
@@ -1195,7 +1220,9 @@ function multiSetWithRetry(data, retryAttempt) {
|
|
|
1195
1220
|
.catch((error) => OnyxUtils.retryOperation(error, multiSetWithRetry, newData, retryAttempt))
|
|
1196
1221
|
.then(() => {
|
|
1197
1222
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.MULTI_SET, undefined, newData);
|
|
1198
|
-
|
|
1223
|
+
return Promise.all(updatePromises);
|
|
1224
|
+
})
|
|
1225
|
+
.then(() => undefined);
|
|
1199
1226
|
}
|
|
1200
1227
|
/**
|
|
1201
1228
|
* Sets a collection by replacing all existing collection members with new values.
|
|
@@ -1248,16 +1275,17 @@ function setCollectionWithRetry({ collectionKey, collection }, retryAttempt) {
|
|
|
1248
1275
|
const previousCollection = OnyxUtils.getCachedCollection(collectionKey);
|
|
1249
1276
|
for (const [key, value] of keyValuePairs)
|
|
1250
1277
|
OnyxCache_1.default.set(key, value);
|
|
1251
|
-
|
|
1278
|
+
const updatePromise = OnyxUtils.scheduleNotifyCollectionSubscribers(collectionKey, mutableCollection, previousCollection);
|
|
1252
1279
|
// RAM-only keys are not supposed to be saved to storage
|
|
1253
1280
|
if (isRamOnlyKey(collectionKey)) {
|
|
1254
1281
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1255
|
-
return;
|
|
1282
|
+
return updatePromise;
|
|
1256
1283
|
}
|
|
1257
1284
|
return storage_1.default.multiSet(keyValuePairs)
|
|
1258
1285
|
.catch((error) => OnyxUtils.retryOperation(error, setCollectionWithRetry, { collectionKey, collection }, retryAttempt))
|
|
1259
1286
|
.then(() => {
|
|
1260
1287
|
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1288
|
+
return updatePromise;
|
|
1261
1289
|
});
|
|
1262
1290
|
});
|
|
1263
1291
|
}
|
|
@@ -1364,7 +1392,7 @@ function mergeCollectionWithPatches({ collectionKey, collection, mergeReplaceNul
|
|
|
1364
1392
|
// and update all subscribers
|
|
1365
1393
|
const promiseUpdate = previousCollectionPromise.then((previousCollection) => {
|
|
1366
1394
|
OnyxCache_1.default.merge(finalMergedCollection);
|
|
1367
|
-
|
|
1395
|
+
return scheduleNotifyCollectionSubscribers(collectionKey, finalMergedCollection, previousCollection);
|
|
1368
1396
|
});
|
|
1369
1397
|
return Promise.all(promises)
|
|
1370
1398
|
.catch((error) => retryOperation(error, mergeCollectionWithPatches, { collectionKey, collection: resultCollection, mergeReplaceNullPatches, isProcessingCollectionUpdate }, retryAttempt))
|
|
@@ -1417,15 +1445,16 @@ function partialSetCollection({ collectionKey, collection }, retryAttempt) {
|
|
|
1417
1445
|
const keyValuePairs = prepareKeyValuePairsForStorage(mutableCollection, true, undefined, true);
|
|
1418
1446
|
for (const [key, value] of keyValuePairs)
|
|
1419
1447
|
OnyxCache_1.default.set(key, value);
|
|
1420
|
-
|
|
1448
|
+
const updatePromise = scheduleNotifyCollectionSubscribers(collectionKey, mutableCollection, previousCollection);
|
|
1421
1449
|
if (isRamOnlyKey(collectionKey)) {
|
|
1422
1450
|
sendActionToDevTools(METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1423
|
-
return;
|
|
1451
|
+
return updatePromise;
|
|
1424
1452
|
}
|
|
1425
1453
|
return storage_1.default.multiSet(keyValuePairs)
|
|
1426
1454
|
.catch((error) => retryOperation(error, partialSetCollection, { collectionKey, collection }, retryAttempt))
|
|
1427
1455
|
.then(() => {
|
|
1428
1456
|
sendActionToDevTools(METHOD.SET_COLLECTION, undefined, mutableCollection);
|
|
1457
|
+
return updatePromise;
|
|
1429
1458
|
});
|
|
1430
1459
|
});
|
|
1431
1460
|
}
|
|
@@ -1469,6 +1498,8 @@ const OnyxUtils = {
|
|
|
1469
1498
|
sendDataToConnection,
|
|
1470
1499
|
getCollectionKey,
|
|
1471
1500
|
getCollectionDataAndSendAsObject,
|
|
1501
|
+
scheduleSubscriberUpdate,
|
|
1502
|
+
scheduleNotifyCollectionSubscribers,
|
|
1472
1503
|
remove,
|
|
1473
1504
|
reportStorageQuota,
|
|
1474
1505
|
retryOperation,
|
|
@@ -1523,6 +1554,10 @@ GlobalSettings.addGlobalSettingsChangeListener(({ enablePerformanceMetrics }) =>
|
|
|
1523
1554
|
// @ts-expect-error Reassign
|
|
1524
1555
|
sendDataToConnection = (0, metrics_1.default)(sendDataToConnection, 'OnyxUtils.sendDataToConnection');
|
|
1525
1556
|
// @ts-expect-error Reassign
|
|
1557
|
+
scheduleSubscriberUpdate = (0, metrics_1.default)(scheduleSubscriberUpdate, 'OnyxUtils.scheduleSubscriberUpdate');
|
|
1558
|
+
// @ts-expect-error Reassign
|
|
1559
|
+
scheduleNotifyCollectionSubscribers = (0, metrics_1.default)(scheduleNotifyCollectionSubscribers, 'OnyxUtils.scheduleNotifyCollectionSubscribers');
|
|
1560
|
+
// @ts-expect-error Reassign
|
|
1526
1561
|
remove = (0, metrics_1.default)(remove, 'OnyxUtils.remove');
|
|
1527
1562
|
// @ts-expect-error Reassign
|
|
1528
1563
|
reportStorageQuota = (0, metrics_1.default)(reportStorageQuota, 'OnyxUtils.reportStorageQuota');
|