react-native-onyx 3.0.37 → 3.0.39

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/README.md CHANGED
@@ -206,21 +206,6 @@ export default App;
206
206
 
207
207
  It's also beneficial to use a [selector](https://github.com/Expensify/react-native-onyx/blob/main/API.md#connectmapping--number) with the mapping in case you need to grab a single item in a collection (like a single report action).
208
208
 
209
- ### useOnyx()'s `canBeMissing` option
210
-
211
- You must pass the `canBeMissing` configuration flag to `useOnyx` if you want the hook to log an alert when data is missing from Onyx store. Regarding usage in `Expensify/App` repo, if the component calling this is the one loading the data by calling an action, then you should set this to `true`. If the component calling this does not load the data then you should set it to `false`, which means that if the data is not there, it will log an alert, as it means we are using data that no one loaded and that's most probably a bug.
212
-
213
- ```javascript
214
- const Component = ({reportID}) => {
215
- // This hook will log an alert (via `Logger.logAlert()`) if `report` is `undefined`.
216
- const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {canBeMissing: false});
217
-
218
- // rest of the component's code.
219
- };
220
-
221
- export default Component;
222
- ```
223
-
224
209
  ## Collections
225
210
 
226
211
  Collections allow keys with similar value types to be subscribed together by subscribing to the collection key. To define one, it must be included in the `ONYXKEYS.COLLECTION` object and it must be suffixed with an underscore. Member keys should use a unique identifier or index after the collection key prefix (e.g. `report_42`).
package/dist/Onyx.js CHANGED
@@ -317,14 +317,7 @@ function clear(keysToPreserve = []) {
317
317
  const newValue = (_a = defaultKeyStates[key]) !== null && _a !== void 0 ? _a : null;
318
318
  if (newValue !== oldValue) {
319
319
  OnyxCache_1.default.set(key, newValue);
320
- let collectionKey;
321
- try {
322
- collectionKey = OnyxUtils_1.default.getCollectionKey(key);
323
- }
324
- catch (e) {
325
- // If getCollectionKey() throws an error it means the key is not a collection key.
326
- collectionKey = undefined;
327
- }
320
+ const collectionKey = OnyxUtils_1.default.getCollectionKey(key);
328
321
  if (collectionKey) {
329
322
  if (!keyValuesToResetAsCollection[collectionKey]) {
330
323
  keyValuesToResetAsCollection[collectionKey] = { oldValues: {}, newValues: {} };
@@ -162,7 +162,7 @@ declare class OnyxCache {
162
162
  /**
163
163
  * Get the collection key for a given member key
164
164
  */
165
- getCollectionKey(key: OnyxKey): OnyxKey | null;
165
+ getCollectionKey(key: OnyxKey): OnyxKey | undefined;
166
166
  /**
167
167
  * Get all data for a collection key
168
168
  */
package/dist/OnyxCache.js CHANGED
@@ -383,7 +383,7 @@ class OnyxCache {
383
383
  return collectionKey;
384
384
  }
385
385
  }
386
- return null;
386
+ return undefined;
387
387
  }
388
388
  /**
389
389
  * Get all data for a collection key
@@ -40,12 +40,11 @@ declare class OnyxSnapshotCache {
40
40
  * - `selector`: Different selectors produce different results, so each selector needs its own cache entry
41
41
  * - `initWithStoredValues`: This flag changes the initial loading behavior and affects the returned fetch status
42
42
  * - `allowStaleData`: Controls whether stale data can be returned during pending merges, affecting result timing
43
- * - `canBeMissing`: Determines logging behavior for missing data, but doesn't affect the actual data returned
44
43
  *
45
44
  * Other options like `canEvict`, `reuseConnection`, and `allowDynamicKey` don't affect the data transformation
46
45
  * or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
47
46
  */
48
- registerConsumer<TKey extends OnyxKey, TReturnValue>(options: Pick<UseOnyxOptions<TKey, TReturnValue>, 'selector' | 'initWithStoredValues' | 'allowStaleData' | 'canBeMissing'>): string;
47
+ registerConsumer<TKey extends OnyxKey, TReturnValue>(options: Pick<UseOnyxOptions<TKey, TReturnValue>, 'selector' | 'initWithStoredValues' | 'allowStaleData'>): string;
49
48
  /**
50
49
  * Deregister a consumer for a cache key.
51
50
  * Decrements reference counter and removes cache entry if no consumers remain.
@@ -37,19 +37,17 @@ class OnyxSnapshotCache {
37
37
  * - `selector`: Different selectors produce different results, so each selector needs its own cache entry
38
38
  * - `initWithStoredValues`: This flag changes the initial loading behavior and affects the returned fetch status
39
39
  * - `allowStaleData`: Controls whether stale data can be returned during pending merges, affecting result timing
40
- * - `canBeMissing`: Determines logging behavior for missing data, but doesn't affect the actual data returned
41
40
  *
42
41
  * Other options like `canEvict`, `reuseConnection`, and `allowDynamicKey` don't affect the data transformation
43
42
  * or timing behavior of getSnapshot, so they're excluded from the cache key for better cache hit rates.
44
43
  */
45
44
  registerConsumer(options) {
46
- var _a, _b, _c;
45
+ var _a, _b;
47
46
  const selectorID = (options === null || options === void 0 ? void 0 : options.selector) ? this.getSelectorID(options.selector) : 'no_selector';
48
47
  // Create options hash without expensive JSON.stringify
49
48
  const initWithStoredValues = (_a = options === null || options === void 0 ? void 0 : options.initWithStoredValues) !== null && _a !== void 0 ? _a : true;
50
49
  const allowStaleData = (_b = options === null || options === void 0 ? void 0 : options.allowStaleData) !== null && _b !== void 0 ? _b : false;
51
- const canBeMissing = (_c = options === null || options === void 0 ? void 0 : options.canBeMissing) !== null && _c !== void 0 ? _c : true;
52
- const cacheKey = `${selectorID}_${initWithStoredValues}_${allowStaleData}_${canBeMissing}`;
50
+ const cacheKey = `${selectorID}_${initWithStoredValues}_${allowStaleData}`;
53
51
  // Increment reference count for this cache key
54
52
  const currentCount = this.cacheKeyRefCounts.get(cacheKey) || 0;
55
53
  this.cacheKeyRefCounts.set(cacheKey, currentCount + 1);
@@ -102,14 +100,11 @@ class OnyxSnapshotCache {
102
100
  invalidateForKey(keyToInvalidate) {
103
101
  // Always invalidate the exact key
104
102
  this.snapshotCache.delete(keyToInvalidate);
105
- try {
106
- // Check if the key is a collection member and invalidate the collection base key
107
- const collectionBaseKey = OnyxUtils_1.default.getCollectionKey(keyToInvalidate);
103
+ // Check if the key is a collection member and invalidate the collection base key
104
+ const collectionBaseKey = OnyxUtils_1.default.getCollectionKey(keyToInvalidate);
105
+ if (collectionBaseKey) {
108
106
  this.snapshotCache.delete(collectionBaseKey);
109
107
  }
110
- catch (e) {
111
- // do nothing - this just means the key is not a collection member
112
- }
113
108
  }
114
109
  /**
115
110
  * Clear all snapshot cache
@@ -163,9 +163,9 @@ declare function isKeyMatch(configKey: OnyxKey, key: OnyxKey): boolean;
163
163
  * - `getCollectionKey("sharedNVP_user_-1_something")` would return "sharedNVP_user_"
164
164
  *
165
165
  * @param key - The collection key to process.
166
- * @returns The plain collection key or throws an Error if the key is not a collection one.
166
+ * @returns The plain collection key or undefined if the key is not a collection one.
167
167
  */
168
- declare function getCollectionKey(key: CollectionKey): string;
168
+ declare function getCollectionKey(key: CollectionKey): string | undefined;
169
169
  /**
170
170
  * Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
171
171
  * If the requested key is a collection, it will return an object with all the collection members.
package/dist/OnyxUtils.js CHANGED
@@ -389,15 +389,9 @@ function isCollectionMemberKey(collectionKey, key) {
389
389
  * @returns true if the key is a collection member, false otherwise
390
390
  */
391
391
  function isCollectionMember(key) {
392
- try {
393
- const collectionKey = getCollectionKey(key);
394
- // If the key is longer than the collection key, it's a collection member
395
- return key.length > collectionKey.length;
396
- }
397
- catch (e) {
398
- // If getCollectionKey throws, the key is not a collection member
399
- return false;
400
- }
392
+ const collectionKey = getCollectionKey(key);
393
+ // If the key is longer than the collection key, it's a collection member
394
+ return !!collectionKey && key.length > collectionKey.length;
401
395
  }
402
396
  /**
403
397
  * Checks if a given key is a RAM-only key, RAM-only collection key, or a RAM-only collection member
@@ -417,14 +411,10 @@ function isCollectionMember(key) {
417
411
  * @returns true if key is a RAM-only key, RAM-only collection key, or a RAM-only collection member
418
412
  */
419
413
  function isRamOnlyKey(key) {
420
- try {
421
- const collectionKey = getCollectionKey(key);
422
- // If collectionKey exists for a given key, check if it's a RAM-only key
414
+ const collectionKey = getCollectionKey(key);
415
+ if (collectionKey) {
423
416
  return OnyxCache_1.default.isRamOnlyKey(collectionKey);
424
417
  }
425
- catch (_a) {
426
- // If getCollectionKey throws, the key is not a collection member
427
- }
428
418
  return OnyxCache_1.default.isRamOnlyKey(key);
429
419
  }
430
420
  /**
@@ -439,8 +429,12 @@ function splitCollectionMemberKey(key, collectionKey) {
439
429
  throw new Error(`Invalid '${collectionKey}' collection key provided, it isn't compatible with '${key}' key.`);
440
430
  }
441
431
  if (!collectionKey) {
432
+ const resolvedKey = getCollectionKey(key);
433
+ if (!resolvedKey) {
434
+ throw new Error(`Invalid '${key}' key provided, only collection keys are allowed.`);
435
+ }
442
436
  // eslint-disable-next-line no-param-reassign
443
- collectionKey = getCollectionKey(key);
437
+ collectionKey = resolvedKey;
444
438
  }
445
439
  return [collectionKey, key.slice(collectionKey.length)];
446
440
  }
@@ -461,7 +455,7 @@ function isKeyMatch(configKey, key) {
461
455
  * - `getCollectionKey("sharedNVP_user_-1_something")` would return "sharedNVP_user_"
462
456
  *
463
457
  * @param key - The collection key to process.
464
- * @returns The plain collection key or throws an Error if the key is not a collection one.
458
+ * @returns The plain collection key or undefined if the key is not a collection one.
465
459
  */
466
460
  function getCollectionKey(key) {
467
461
  // Start by finding the position of the last underscore in the string
@@ -477,7 +471,7 @@ function getCollectionKey(key) {
477
471
  // Move to the next underscore to check smaller possible keys
478
472
  lastUnderscoreIndex = key.lastIndexOf('_', lastUnderscoreIndex - 1);
479
473
  }
480
- throw new Error(`Invalid '${key}' key provided, only collection keys are allowed.`);
474
+ return undefined;
481
475
  }
482
476
  /**
483
477
  * Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
@@ -625,14 +619,7 @@ function keyChanged(key, value, canUpdateSubscriber = () => true, isProcessingCo
625
619
  // do the same in keysChanged, because we only call that function when a collection key changes, and it doesn't happen that often.
626
620
  // For performance reason, we look for the given key and later if don't find it we look for the collection key, instead of checking if it is a collection key first.
627
621
  let stateMappingKeys = (_a = onyxKeyToSubscriptionIDs.get(key)) !== null && _a !== void 0 ? _a : [];
628
- let collectionKey;
629
- try {
630
- collectionKey = getCollectionKey(key);
631
- }
632
- catch (e) {
633
- // If getCollectionKey() throws an error it means the key is not a collection key.
634
- collectionKey = undefined;
635
- }
622
+ const collectionKey = getCollectionKey(key);
636
623
  if (collectionKey) {
637
624
  // Getting the collection key from the specific key because only collection keys were stored in the mapping.
638
625
  stateMappingKeys = [...stateMappingKeys, ...((_b = onyxKeyToSubscriptionIDs.get(collectionKey)) !== null && _b !== void 0 ? _b : [])];
package/dist/useOnyx.d.ts CHANGED
@@ -24,13 +24,6 @@ type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = {
24
24
  * If set to `true`, the key can be changed dynamically during the component lifecycle.
25
25
  */
26
26
  allowDynamicKey?: boolean;
27
- /**
28
- * If the component calling this is the one loading the data by calling an action, then you should set this to `true`.
29
- *
30
- * If the component calling this does not load the data then you should set it to `false`, which means that if the data
31
- * is not there, it will log an alert, as it means we are using data that no one loaded and that's most probably a bug.
32
- */
33
- canBeMissing?: boolean;
34
27
  /**
35
28
  * This will be used to subscribe to a subset of an Onyx key's data.
36
29
  * Using this setting on `useOnyx` can have very positive performance benefits because the component will only re-render
package/dist/useOnyx.js CHANGED
@@ -44,7 +44,6 @@ const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
44
44
  const GlobalSettings = __importStar(require("./GlobalSettings"));
45
45
  const usePrevious_1 = __importDefault(require("./usePrevious"));
46
46
  const metrics_1 = __importDefault(require("./metrics"));
47
- const Logger = __importStar(require("./Logger"));
48
47
  const OnyxSnapshotCache_1 = __importDefault(require("./OnyxSnapshotCache"));
49
48
  const useLiveRef_1 = __importDefault(require("./useLiveRef"));
50
49
  function useOnyx(key, options, dependencies = []) {
@@ -111,8 +110,7 @@ function useOnyx(key, options, dependencies = []) {
111
110
  selector: options === null || options === void 0 ? void 0 : options.selector,
112
111
  initWithStoredValues: options === null || options === void 0 ? void 0 : options.initWithStoredValues,
113
112
  allowStaleData: options === null || options === void 0 ? void 0 : options.allowStaleData,
114
- canBeMissing: options === null || options === void 0 ? void 0 : options.canBeMissing,
115
- }), [options === null || options === void 0 ? void 0 : options.selector, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.allowStaleData, options === null || options === void 0 ? void 0 : options.canBeMissing]);
113
+ }), [options === null || options === void 0 ? void 0 : options.selector, options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.allowStaleData]);
116
114
  (0, react_1.useEffect)(() => () => OnyxSnapshotCache_1.default.deregisterConsumer(key, cacheKey), [key, cacheKey]);
117
115
  (0, react_1.useEffect)(() => {
118
116
  // These conditions will ensure we can only handle dynamic collection member keys from the same collection.
@@ -178,7 +176,6 @@ function useOnyx(key, options, dependencies = []) {
178
176
  return cachedResult;
179
177
  }
180
178
  }
181
- let isOnyxValueDefined = true;
182
179
  // We return the initial result right away during the first connection if `initWithStoredValues` is set to `false`.
183
180
  if (isFirstConnectionRef.current && (options === null || options === void 0 ? void 0 : options.initWithStoredValues) === false) {
184
181
  const result = resultRef.current;
@@ -194,9 +191,6 @@ function useOnyx(key, options, dependencies = []) {
194
191
  const value = OnyxUtils_1.default.tryGetCachedValue(key);
195
192
  const selectedValue = memoizedSelector ? memoizedSelector(value) : value;
196
193
  newValueRef.current = (selectedValue !== null && selectedValue !== void 0 ? selectedValue : undefined);
197
- // This flag is `false` when the original Onyx value (without selector) is not defined yet.
198
- // It will be used later to check if we need to log an alert that the value is missing.
199
- isOnyxValueDefined = value !== null && value !== undefined;
200
194
  // We set this flag to `false` again since we don't want to get the newest cached value every time `getSnapshot()` is executed,
201
195
  // and only when `Onyx.connect()` callback is fired.
202
196
  shouldGetCachedValueRef.current = false;
@@ -243,18 +237,12 @@ function useOnyx(key, options, dependencies = []) {
243
237
  sourceValue: sourceValueRef.current,
244
238
  },
245
239
  ];
246
- // If `canBeMissing` is set to `false` and the Onyx value of that key is not defined,
247
- // we log an alert so it can be acknowledged by the consumer. Additionally, we won't log alerts
248
- // if there's a `Onyx.clear()` task in progress.
249
- if ((options === null || options === void 0 ? void 0 : options.canBeMissing) === false && newFetchStatus === 'loaded' && !isOnyxValueDefined && !OnyxCache_1.default.hasPendingTask(OnyxCache_1.TASK.CLEAR)) {
250
- Logger.logAlert(`useOnyx returned no data for key with canBeMissing set to false for key ${key}`, { showAlert: true });
251
- }
252
240
  }
253
241
  if (newFetchStatus !== 'loading') {
254
242
  OnyxSnapshotCache_1.default.setCachedResult(key, cacheKey, resultRef.current);
255
243
  }
256
244
  return resultRef.current;
257
- }, [options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.allowStaleData, options === null || options === void 0 ? void 0 : options.canBeMissing, key, memoizedSelector, cacheKey, previousKey]);
245
+ }, [options === null || options === void 0 ? void 0 : options.initWithStoredValues, options === null || options === void 0 ? void 0 : options.allowStaleData, key, memoizedSelector, cacheKey, previousKey]);
258
246
  const subscribe = (0, react_1.useCallback)((onStoreChange) => {
259
247
  isConnectingRef.current = true;
260
248
  onStoreChangeFnRef.current = onStoreChange;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-onyx",
3
- "version": "3.0.37",
3
+ "version": "3.0.39",
4
4
  "author": "Expensify, Inc.",
5
5
  "homepage": "https://expensify.com",
6
6
  "description": "State management for React Native",