react-native-onyx 2.0.47 → 2.0.49

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
@@ -28,6 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  /* eslint-disable no-continue */
30
30
  const underscore_1 = __importDefault(require("underscore"));
31
+ const pick_1 = __importDefault(require("lodash/pick"));
31
32
  const Logger = __importStar(require("./Logger"));
32
33
  const OnyxCache_1 = __importDefault(require("./OnyxCache"));
33
34
  const createDeferredTask_1 = __importDefault(require("./createDeferredTask"));
@@ -501,7 +502,7 @@ function clear(keysToPreserve = []) {
501
502
  // since collection key subscribers need to be updated differently
502
503
  if (!isKeyToPreserve) {
503
504
  const oldValue = OnyxCache_1.default.get(key);
504
- const newValue = (_a = defaultKeyStates[key]) !== null && _a !== void 0 ? _a : undefined;
505
+ const newValue = (_a = defaultKeyStates[key]) !== null && _a !== void 0 ? _a : null;
505
506
  if (newValue !== oldValue) {
506
507
  OnyxCache_1.default.set(key, newValue);
507
508
  const collectionKey = key.substring(0, key.indexOf('_') + 1);
@@ -509,10 +510,10 @@ function clear(keysToPreserve = []) {
509
510
  if (!keyValuesToResetAsCollection[collectionKey]) {
510
511
  keyValuesToResetAsCollection[collectionKey] = {};
511
512
  }
512
- keyValuesToResetAsCollection[collectionKey][key] = newValue;
513
+ keyValuesToResetAsCollection[collectionKey][key] = newValue !== null && newValue !== void 0 ? newValue : undefined;
513
514
  }
514
515
  else {
515
- keyValuesToResetIndividually[key] = newValue;
516
+ keyValuesToResetIndividually[key] = newValue !== null && newValue !== void 0 ? newValue : undefined;
516
517
  }
517
518
  }
518
519
  }
@@ -549,6 +550,36 @@ function clear(keysToPreserve = []) {
549
550
  })
550
551
  .then(() => undefined);
551
552
  }
553
+ function updateSnapshots(data) {
554
+ const snapshotCollectionKey = OnyxUtils_1.default.getSnapshotKey();
555
+ if (!snapshotCollectionKey)
556
+ return;
557
+ const promises = [];
558
+ const snapshotCollection = OnyxUtils_1.default.getCachedCollection(snapshotCollectionKey);
559
+ Object.entries(snapshotCollection).forEach(([snapshotKey, snapshotValue]) => {
560
+ // Snapshots may not be present in cache. We don't know how to update them so we skip.
561
+ if (!snapshotValue) {
562
+ return;
563
+ }
564
+ let updatedData = {};
565
+ data.forEach(({ key, value }) => {
566
+ // snapshots are normal keys so we want to skip update if they are written to Onyx
567
+ if (OnyxUtils_1.default.isCollectionMemberKey(snapshotCollectionKey, key)) {
568
+ return;
569
+ }
570
+ if (typeof snapshotValue !== 'object' || !('data' in snapshotValue)) {
571
+ return;
572
+ }
573
+ const snapshotData = snapshotValue.data;
574
+ if (!snapshotData || !snapshotData[key]) {
575
+ return;
576
+ }
577
+ updatedData = Object.assign(Object.assign({}, updatedData), { [key]: (0, pick_1.default)(value, Object.keys(snapshotData[key])) });
578
+ });
579
+ promises.push(() => merge(snapshotKey, { data: updatedData }));
580
+ });
581
+ return Promise.all(promises.map((p) => p()));
582
+ }
552
583
  /**
553
584
  * Insert API responses and lifecycle data into Onyx
554
585
  *
@@ -595,7 +626,10 @@ function update(data) {
595
626
  break;
596
627
  }
597
628
  });
598
- return clearPromise.then(() => Promise.all(promises.map((p) => p()))).then(() => undefined);
629
+ return clearPromise
630
+ .then(() => Promise.all(promises.map((p) => p())))
631
+ .then(() => updateSnapshots(data))
632
+ .then(() => undefined);
599
633
  }
600
634
  const Onyx = {
601
635
  METHOD: OnyxUtils_1.default.METHOD,
@@ -9,6 +9,7 @@ declare const METHOD: {
9
9
  readonly CLEAR: "clear";
10
10
  };
11
11
  type OnyxMethod = ValueOf<typeof METHOD>;
12
+ declare function getSnapshotKey(): OnyxKey | null;
12
13
  /**
13
14
  * Getter - returns the merge queue.
14
15
  */
@@ -235,5 +236,6 @@ declare const OnyxUtils: {
235
236
  prepareKeyValuePairsForStorage: typeof prepareKeyValuePairsForStorage;
236
237
  applyMerge: typeof applyMerge;
237
238
  initializeWithDefaultKeyStates: typeof initializeWithDefaultKeyStates;
239
+ getSnapshotKey: typeof getSnapshotKey;
238
240
  };
239
241
  export default OnyxUtils;
package/dist/OnyxUtils.js CHANGED
@@ -65,6 +65,10 @@ const evictionBlocklist = {};
65
65
  let defaultKeyStates = {};
66
66
  let batchUpdatesPromise = null;
67
67
  let batchUpdatesQueue = [];
68
+ let snapshotKey = null;
69
+ function getSnapshotKey() {
70
+ return snapshotKey;
71
+ }
68
72
  /**
69
73
  * Getter - returns the merge queue.
70
74
  */
@@ -110,6 +114,9 @@ function initStoreValues(keys, initialKeyStates, safeEvictionKeys) {
110
114
  DevTools_1.default.initState(initialKeyStates);
111
115
  // Let Onyx know about which keys are safe to evict
112
116
  evictionAllowList = safeEvictionKeys;
117
+ if (typeof keys.COLLECTION === 'object' && typeof keys.COLLECTION.SNAPSHOT === 'string') {
118
+ snapshotKey = keys.COLLECTION.SNAPSHOT;
119
+ }
113
120
  }
114
121
  function sendActionToDevTools(method, key, value, mergedValue = undefined) {
115
122
  DevTools_1.default.registerAction(utils_1.default.formatActionName(method, key), value, key ? { [key]: mergedValue || value } : value);
@@ -931,5 +938,6 @@ const OnyxUtils = {
931
938
  prepareKeyValuePairsForStorage,
932
939
  applyMerge,
933
940
  initializeWithDefaultKeyStates,
941
+ getSnapshotKey,
934
942
  };
935
943
  exports.default = OnyxUtils;
package/dist/useOnyx.js CHANGED
@@ -9,8 +9,10 @@ const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
9
9
  const useLiveRef_1 = __importDefault(require("./useLiveRef"));
10
10
  const usePrevious_1 = __importDefault(require("./usePrevious"));
11
11
  const Onyx_1 = __importDefault(require("./Onyx"));
12
+ const OnyxCache_1 = __importDefault(require("./OnyxCache"));
12
13
  function getCachedValue(key, selector) {
13
- return OnyxUtils_1.default.tryGetCachedValue(key, { selector });
14
+ var _a;
15
+ return ((_a = OnyxUtils_1.default.tryGetCachedValue(key, { selector })) !== null && _a !== void 0 ? _a : undefined);
14
16
  }
15
17
  function useOnyx(key, options) {
16
18
  const connectionIDRef = (0, react_1.useRef)(null);
@@ -18,8 +20,8 @@ function useOnyx(key, options) {
18
20
  // Used to stabilize the selector reference and avoid unnecessary calls to `getSnapshot()`.
19
21
  const selectorRef = (0, useLiveRef_1.default)(options === null || options === void 0 ? void 0 : options.selector);
20
22
  // Stores the previous cached value as it's necessary to compare with the new value in `getSnapshot()`.
21
- // We initialize it to `undefined` to simulate that we don't have any value from cache yet.
22
- const cachedValueRef = (0, react_1.useRef)(undefined);
23
+ // We initialize it to `null` to simulate that we don't have any value from cache yet.
24
+ const cachedValueRef = (0, react_1.useRef)(null);
23
25
  // Stores the previously result returned by the hook, containing the data from cache and the fetch status.
24
26
  // We initialize it to `undefined` and `loading` fetch status to simulate the initial result when the hook is loading from the cache.
25
27
  // However, if `initWithStoredValues` is `true` we set the fetch status to `loaded` since we want to signal that data is ready.
@@ -50,13 +52,14 @@ function useOnyx(key, options) {
50
52
  throw new Error(`'${previousKey}' key can't be changed to '${key}'. useOnyx() only supports dynamic keys if they are both collection member keys from the same collection e.g. from 'collection_id1' to 'collection_id2'.`);
51
53
  }, [previousKey, key]);
52
54
  const getSnapshot = (0, react_1.useCallback)(() => {
53
- var _a;
55
+ var _a, _b;
54
56
  // We get the value from the cache, supplying a selector too in case it's defined.
55
57
  // If `newValue` is `undefined` it means that the cache doesn't have a value for that key yet.
56
- // If `newValue` is `null` or any other value if means that the cache does have a value for that key.
58
+ // If `newValue` is `null` or any other value it means that the cache does have a value for that key.
57
59
  // This difference between `undefined` and other values is crucial and it's used to address the following
58
60
  // conditions and use cases.
59
61
  let newValue = getCachedValue(key, selectorRef.current);
62
+ const hasCacheForKey = OnyxCache_1.default.hasCacheForKey(key);
60
63
  // Since the fetch status can be different given the use cases below, we define the variable right away.
61
64
  let newFetchStatus;
62
65
  // If we have pending merge operations for the key during the first connection, we set the new value to `undefined`
@@ -66,18 +69,19 @@ function useOnyx(key, options) {
66
69
  newValue = undefined;
67
70
  newFetchStatus = 'loading';
68
71
  }
69
- // If data is not present in cache (if it's `undefined`) and `initialValue` is set during the first connection,
72
+ // If data is not present in cache and `initialValue` is set during the first connection,
70
73
  // we set the new value to `initialValue` and fetch status to `loaded` since we already have some data to return to the consumer.
71
- if (isFirstConnectionRef.current && newValue === undefined && (options === null || options === void 0 ? void 0 : options.initialValue) !== undefined) {
72
- newValue = options === null || options === void 0 ? void 0 : options.initialValue;
74
+ if (isFirstConnectionRef.current && !hasCacheForKey && (options === null || options === void 0 ? void 0 : options.initialValue) !== undefined) {
75
+ newValue = ((_a = options === null || options === void 0 ? void 0 : options.initialValue) !== null && _a !== void 0 ? _a : undefined);
73
76
  newFetchStatus = 'loaded';
74
77
  }
75
78
  // If the previously cached value is different from the new value, we update both cached value
76
79
  // and the result to be returned by the hook.
77
- if (!(0, fast_equals_1.deepEqual)(cachedValueRef.current, newValue)) {
80
+ // If the cache was set for the first time, we also update the cached value and the result.
81
+ const isCacheSetFirstTime = cachedValueRef.current === null && hasCacheForKey;
82
+ if (isCacheSetFirstTime || !(0, fast_equals_1.deepEqual)((_b = cachedValueRef.current) !== null && _b !== void 0 ? _b : undefined, newValue)) {
78
83
  cachedValueRef.current = newValue;
79
- // If the new value is `null` we default it to `undefined` to ensure the consumer get a consistent result from the hook.
80
- resultRef.current = [((_a = cachedValueRef.current) !== null && _a !== void 0 ? _a : undefined), { status: newFetchStatus !== null && newFetchStatus !== void 0 ? newFetchStatus : 'loaded' }];
84
+ resultRef.current = [cachedValueRef.current, { status: newFetchStatus !== null && newFetchStatus !== void 0 ? newFetchStatus : 'loaded' }];
81
85
  }
82
86
  return resultRef.current;
83
87
  }, [key, selectorRef, options === null || options === void 0 ? void 0 : options.allowStaleData, options === null || options === void 0 ? void 0 : options.initialValue]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "2.0.47",
3
+ "version": "2.0.49",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",