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 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
- // Notify the subscribers for each key/value group so they can receive the new values
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);
@@ -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 };
@@ -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
- value = value === null ? undefined : value;
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) && (0, fast_equals_1.shallowEqual)(lastValue, value)) {
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, value, matchedKey);
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
- sendDataToConnection(mapping, mapping.key);
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
- keyChanged(key, undefined, undefined, isProcessingCollectionUpdate);
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
- keyChanged(key, value, (subscriber) => hasChanged || (subscriber === null || subscriber === void 0 ? void 0 : subscriber.initWithStoredValues) === false);
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 matchingKeys) {
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 Promise.resolve();
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 Promise.resolve();
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
- for (const [key, value] of keyValuePairsToSet) {
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
- keyChanged(key, value);
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
- keysChanged(collectionKey, mutableCollection, previousCollection);
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
- keysChanged(collectionKey, finalMergedCollection, previousCollection);
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
- keysChanged(collectionKey, mutableCollection, previousCollection);
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');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "3.0.49",
3
+ "version": "3.0.50",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",