react-native-onyx 1.0.55 → 1.0.56

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.
@@ -268,6 +268,46 @@ function isSafeEvictionKey(testKey) {
268
268
  return underscore__WEBPACK_IMPORTED_MODULE_2___default().some(evictionAllowList, (key) => isKeyMatch(key, testKey));
269
269
  }
270
270
 
271
+ /**
272
+ * Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
273
+ * If the requested key is a collection, it will return an object with all the collection members.
274
+ *
275
+ * @param {String} key
276
+ * @param {Object} mapping
277
+ * @returns {Mixed}
278
+ */
279
+ function tryGetCachedValue(key) {let mapping = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
280
+ let val = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].getValue(key);
281
+
282
+ if (isCollectionKey(key)) {
283
+ const allKeys = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].getAllKeys();
284
+ const matchingKeys = underscore__WEBPACK_IMPORTED_MODULE_2___default().filter(allKeys, (k) => k.startsWith(key));
285
+ const values = underscore__WEBPACK_IMPORTED_MODULE_2___default().reduce(matchingKeys, (finalObject, matchedKey) => {
286
+ const cachedValue = _OnyxCache__WEBPACK_IMPORTED_MODULE_4__["default"].getValue(matchedKey);
287
+ if (cachedValue) {
288
+ // This is permissible because we're in the process of constructing the final object in a reduce function.
289
+ // eslint-disable-next-line no-param-reassign
290
+ finalObject[matchedKey] = cachedValue;
291
+ }
292
+ return finalObject;
293
+ }, {});
294
+ if (underscore__WEBPACK_IMPORTED_MODULE_2___default().isEmpty(values)) {
295
+ return;
296
+ }
297
+ val = values;
298
+ }
299
+
300
+ if (mapping.selector) {
301
+ const state = mapping.withOnyxInstance ? mapping.withOnyxInstance.state : undefined;
302
+ if (isCollectionKey(key)) {
303
+ return reduceCollectionWithSelector(val, mapping.selector, state);
304
+ }
305
+ return getSubsetOfData(val, mapping.selector, state);
306
+ }
307
+
308
+ return val;
309
+ }
310
+
271
311
  /**
272
312
  * Remove a key from the recently accessed key list.
273
313
  *
@@ -1436,7 +1476,8 @@ const Onyx = {
1436
1476
  removeFromEvictionBlockList,
1437
1477
  isSafeEvictionKey,
1438
1478
  METHOD,
1439
- setMemoryOnlyKeys
1479
+ setMemoryOnlyKeys,
1480
+ tryGetCachedValue
1440
1481
  };
1441
1482
 
1442
1483
  /**
@@ -2402,13 +2443,25 @@ function getDisplayName(component) {
2402
2443
  // disconnected. It is a key value store with the format {[mapping.key]: connectionID}.
2403
2444
  this.activeConnectionIDs = {};
2404
2445
 
2446
+ const cachedState = underscore__WEBPACK_IMPORTED_MODULE_2___default().reduce(mapOnyxToState, (resultObj, mapping, propertyName) => {
2447
+ const key = _Str__WEBPACK_IMPORTED_MODULE_3__.result(mapping.key, props);
2448
+ const value = _Onyx__WEBPACK_IMPORTED_MODULE_4__["default"].tryGetCachedValue(key, mapping);
2449
+
2450
+ if (value !== undefined) {
2451
+ // eslint-disable-next-line no-param-reassign
2452
+ resultObj[propertyName] = value;
2453
+ }
2454
+
2455
+ return resultObj;
2456
+ }, {});
2457
+
2458
+ // If we have all the data we need, then we can render the component immediately
2459
+ cachedState.loading = underscore__WEBPACK_IMPORTED_MODULE_2___default().size(cachedState) < requiredKeysForInit.length;
2460
+
2405
2461
  // Object holding the temporary initial state for the component while we load the various Onyx keys
2406
- this.tempState = {};
2462
+ this.tempState = cachedState;
2407
2463
 
2408
- this.state = {
2409
- // If there are no required keys for init then we can render the wrapped component immediately
2410
- loading: requiredKeysForInit.length > 0
2411
- };
2464
+ this.state = cachedState;
2412
2465
  }
2413
2466
 
2414
2467
  componentDidMount() {
@@ -2425,7 +2478,6 @@ function getDisplayName(component) {
2425
2478
  underscore__WEBPACK_IMPORTED_MODULE_2___default().each(mapOnyxToState, (mapping, propertyName) => {
2426
2479
  const previousKey = _Str__WEBPACK_IMPORTED_MODULE_3__.result(mapping.key, prevProps);
2427
2480
  const newKey = _Str__WEBPACK_IMPORTED_MODULE_3__.result(mapping.key, this.props);
2428
-
2429
2481
  if (previousKey !== newKey) {
2430
2482
  _Onyx__WEBPACK_IMPORTED_MODULE_4__["default"].disconnect(this.activeConnectionIDs[previousKey], previousKey);
2431
2483
  delete this.activeConnectionIDs[previousKey];
@@ -2453,6 +2505,16 @@ function getDisplayName(component) {
2453
2505
  * @param {*} val
2454
2506
  */
2455
2507
  setWithOnyxState(statePropertyName, val) {
2508
+ // We might have loaded the values for the onyx keys/mappings already from the cache.
2509
+ // In case we were able to load all the values upfront, the loading state will be false.
2510
+ // However, Onyx.js will always call setWithOnyxState, as it doesn't know that this implementation
2511
+ // already loaded the values from cache. Thus we have to check whether the value has changed
2512
+ // before we set the state to prevent unnecessary renders.
2513
+ const prevValue = this.state[statePropertyName];
2514
+ if (!this.state.loading && prevValue === val) {
2515
+ return;
2516
+ }
2517
+
2456
2518
  if (!this.state.loading) {
2457
2519
  this.setState({ [statePropertyName]: val });
2458
2520
  return;
@@ -2465,7 +2527,14 @@ function getDisplayName(component) {
2465
2527
  return;
2466
2528
  }
2467
2529
 
2468
- this.setState({ ...this.tempState, loading: false });
2530
+ const stateUpdate = { ...this.tempState, loading: false };
2531
+
2532
+ // The state is set here manually, instead of using setState because setState is an async operation, meaning it might execute on the next tick,
2533
+ // or at a later point in the microtask queue. That can lead to a race condition where
2534
+ // setWithOnyxState is called before the state is actually set. This results in unreliable behavior when checking the loading state and has been mainly observed on fabric.
2535
+ this.state = stateUpdate;
2536
+
2537
+ this.setState(stateUpdate); // Trigger a render
2469
2538
  delete this.tempState;
2470
2539
  }
2471
2540