react-native-onyx 2.0.35 → 2.0.37
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.d.ts +3 -3
- package/dist/Onyx.js +5 -2
- package/dist/OnyxUtils.d.ts +4 -4
- package/dist/OnyxUtils.js +40 -26
- package/dist/types.d.ts +17 -9
- package/dist/useOnyx.d.ts +15 -5
- package/dist/useOnyx.js +4 -4
- package/dist/withOnyx.d.ts +2 -0
- package/package.json +2 -2
package/dist/Onyx.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Logger from './Logger';
|
|
2
|
-
import type { Collection, CollectionKeyBase, ConnectOptions, InitOptions, KeyValueMapping, Mapping, NullableKeyValueMapping, NullishDeep, OnyxEntry, OnyxKey, OnyxUpdate } from './types';
|
|
2
|
+
import type { Collection, CollectionKeyBase, ConnectOptions, InitOptions, KeyValueMapping, Mapping, NonUndefined, NullableKeyValueMapping, NullishDeep, OnyxEntry, OnyxKey, OnyxUpdate } from './types';
|
|
3
3
|
/** Initialize the store with actions and listening for storage events */
|
|
4
4
|
declare function init({ keys, initialKeyStates, safeEvictionKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, }: InitOptions): void;
|
|
5
5
|
/**
|
|
@@ -45,7 +45,7 @@ declare function disconnect(connectionID: number, keyToRemoveFromEvictionBlockli
|
|
|
45
45
|
* @param key ONYXKEY to set
|
|
46
46
|
* @param value value to store
|
|
47
47
|
*/
|
|
48
|
-
declare function set<TKey extends OnyxKey>(key: TKey, value: OnyxEntry<KeyValueMapping[TKey]
|
|
48
|
+
declare function set<TKey extends OnyxKey>(key: TKey, value: NonUndefined<OnyxEntry<KeyValueMapping[TKey]>>): Promise<void>;
|
|
49
49
|
/**
|
|
50
50
|
* Sets multiple keys and values
|
|
51
51
|
*
|
|
@@ -70,7 +70,7 @@ declare function multiSet(data: Partial<NullableKeyValueMapping>): Promise<void>
|
|
|
70
70
|
* Onyx.merge(ONYXKEYS.POLICY, {id: 1}); // -> {id: 1}
|
|
71
71
|
* Onyx.merge(ONYXKEYS.POLICY, {name: 'My Workspace'}); // -> {id: 1, name: 'My Workspace'}
|
|
72
72
|
*/
|
|
73
|
-
declare function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxEntry<NullishDeep<KeyValueMapping[TKey]
|
|
73
|
+
declare function merge<TKey extends OnyxKey>(key: TKey, changes: NonUndefined<OnyxEntry<NullishDeep<KeyValueMapping[TKey]>>>): Promise<void>;
|
|
74
74
|
/**
|
|
75
75
|
* Merges a collection based on their keys
|
|
76
76
|
*
|
package/dist/Onyx.js
CHANGED
|
@@ -401,6 +401,9 @@ function mergeCollection(collectionKey, collection) {
|
|
|
401
401
|
// because we will simply overwrite the existing values in storage.
|
|
402
402
|
const keyValuePairsForNewCollection = OnyxUtils_1.default.prepareKeyValuePairsForStorage(newCollection, true);
|
|
403
403
|
const promises = [];
|
|
404
|
+
// We need to get the previously existing values so we can compare the new ones
|
|
405
|
+
// against them, to avoid unnecessary subscriber updates.
|
|
406
|
+
const previousCollectionPromise = Promise.all(existingKeys.map((key) => OnyxUtils_1.default.get(key).then((value) => [key, value]))).then(Object.fromEntries);
|
|
404
407
|
// New keys will be added via multiSet while existing keys will be updated using multiMerge
|
|
405
408
|
// This is because setting a key that doesn't exist yet with multiMerge will throw errors
|
|
406
409
|
if (keyValuePairsForExistingCollection.length > 0) {
|
|
@@ -413,9 +416,9 @@ function mergeCollection(collectionKey, collection) {
|
|
|
413
416
|
const finalMergedCollection = Object.assign(Object.assign({}, existingKeyCollection), newCollection);
|
|
414
417
|
// Prefill cache if necessary by calling get() on any existing keys and then merge original data to cache
|
|
415
418
|
// and update all subscribers
|
|
416
|
-
const promiseUpdate =
|
|
419
|
+
const promiseUpdate = previousCollectionPromise.then((previousCollection) => {
|
|
417
420
|
OnyxCache_1.default.merge(finalMergedCollection);
|
|
418
|
-
return OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(collectionKey, finalMergedCollection);
|
|
421
|
+
return OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(collectionKey, finalMergedCollection, previousCollection);
|
|
419
422
|
});
|
|
420
423
|
return Promise.all(promises)
|
|
421
424
|
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, mergeCollection, collectionKey, mergedCollection))
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -107,14 +107,14 @@ declare function getCachedCollection<TKey extends CollectionKeyBase>(collectionK
|
|
|
107
107
|
/**
|
|
108
108
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
109
109
|
*/
|
|
110
|
-
declare function keysChanged<TKey extends CollectionKeyBase>(collectionKey: TKey, partialCollection: OnyxCollection<KeyValueMapping[TKey]>, notifyRegularSubscibers?: boolean, notifyWithOnyxSubscibers?: boolean): void;
|
|
110
|
+
declare function keysChanged<TKey extends CollectionKeyBase>(collectionKey: TKey, partialCollection: OnyxCollection<KeyValueMapping[TKey]>, previousPartialCollection: OnyxCollection<KeyValueMapping[TKey]> | undefined, notifyRegularSubscibers?: boolean, notifyWithOnyxSubscibers?: boolean): void;
|
|
111
111
|
/**
|
|
112
112
|
* When a key change happens, search for any callbacks matching the key or collection key and trigger those callbacks
|
|
113
113
|
*
|
|
114
114
|
* @example
|
|
115
115
|
* keyChanged(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
116
116
|
*/
|
|
117
|
-
declare function keyChanged<TKey extends OnyxKey>(key: TKey,
|
|
117
|
+
declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, previousValue: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: Mapping<OnyxKey>) => boolean, notifyRegularSubscibers?: boolean, notifyWithOnyxSubscibers?: boolean): void;
|
|
118
118
|
/**
|
|
119
119
|
* Sends the data obtained from the keys to the connection. It either:
|
|
120
120
|
* - sets state on the withOnyxInstances
|
|
@@ -136,13 +136,13 @@ declare function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matching
|
|
|
136
136
|
* @example
|
|
137
137
|
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
138
138
|
*/
|
|
139
|
-
declare function scheduleSubscriberUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>,
|
|
139
|
+
declare function scheduleSubscriberUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, previousValue: OnyxValue<TKey>, canUpdateSubscriber?: (subscriber?: Mapping<OnyxKey>) => boolean): Promise<void>;
|
|
140
140
|
/**
|
|
141
141
|
* This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
|
|
142
142
|
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
143
143
|
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
144
144
|
*/
|
|
145
|
-
declare function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(key: TKey, value: OnyxCollection<KeyValueMapping[TKey]>): Promise<void>;
|
|
145
|
+
declare function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(key: TKey, value: OnyxCollection<KeyValueMapping[TKey]>, previousValue?: OnyxCollection<KeyValueMapping[TKey]>): Promise<void>;
|
|
146
146
|
/**
|
|
147
147
|
* Remove a key from Onyx and update the subscribers
|
|
148
148
|
*/
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -338,7 +338,16 @@ function getCachedCollection(collectionKey, collectionMemberKeys) {
|
|
|
338
338
|
/**
|
|
339
339
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
340
340
|
*/
|
|
341
|
-
function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
|
|
341
|
+
function keysChanged(collectionKey, partialCollection, previousPartialCollection, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
|
|
342
|
+
const previousCollectionWithoutNestedNulls = previousPartialCollection === undefined ? {} : utils_1.default.removeNestedNullValues(previousPartialCollection);
|
|
343
|
+
// We prepare the "cached collection" which is the entire collection + the new partial data that
|
|
344
|
+
// was merged in via mergeCollection().
|
|
345
|
+
const cachedCollection = getCachedCollection(collectionKey);
|
|
346
|
+
const cachedCollectionWithoutNestedNulls = utils_1.default.removeNestedNullValues(cachedCollection);
|
|
347
|
+
// If the previous collection equals the new collection then we do not need to notify any subscribers.
|
|
348
|
+
if (previousPartialCollection !== undefined && (0, fast_equals_1.deepEqual)(cachedCollectionWithoutNestedNulls, previousCollectionWithoutNestedNulls)) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
342
351
|
// We are iterating over all subscribers similar to keyChanged(). However, we are looking for subscribers who are subscribing to either a collection key or
|
|
343
352
|
// individual collection key member for the collection that is being updated. It is important to note that the collection parameter cane be a PARTIAL collection
|
|
344
353
|
// and does not represent all of the combined keys and values for a collection key. It is just the "new" data that was merged in via mergeCollection().
|
|
@@ -360,10 +369,6 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
360
369
|
* e.g. Onyx.connect({key: `${ONYXKEYS.COLLECTION.REPORT}{reportID}`, callback: ...});
|
|
361
370
|
*/
|
|
362
371
|
const isSubscribedToCollectionMemberKey = isCollectionMemberKey(collectionKey, subscriber.key);
|
|
363
|
-
// We prepare the "cached collection" which is the entire collection + the new partial data that
|
|
364
|
-
// was merged in via mergeCollection().
|
|
365
|
-
const cachedCollection = getCachedCollection(collectionKey);
|
|
366
|
-
const cachedCollectionWithoutNestedNulls = utils_1.default.removeNestedNullValues(cachedCollection);
|
|
367
372
|
// Regular Onyx.connect() subscriber found.
|
|
368
373
|
if (typeof subscriber.callback === 'function') {
|
|
369
374
|
if (!notifyRegularSubscibers) {
|
|
@@ -381,6 +386,9 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
381
386
|
const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
|
|
382
387
|
for (let j = 0; j < dataKeys.length; j++) {
|
|
383
388
|
const dataKey = dataKeys[j];
|
|
389
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollectionWithoutNestedNulls[dataKey], previousCollectionWithoutNestedNulls[dataKey])) {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
384
392
|
subscriber.callback(cachedCollectionWithoutNestedNulls[dataKey], dataKey);
|
|
385
393
|
}
|
|
386
394
|
continue;
|
|
@@ -388,6 +396,9 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
388
396
|
// And if the subscriber is specifically only tracking a particular collection member key then we will
|
|
389
397
|
// notify them with the cached data for that key only.
|
|
390
398
|
if (isSubscribedToCollectionMemberKey) {
|
|
399
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollectionWithoutNestedNulls[subscriber.key], previousCollectionWithoutNestedNulls[subscriber.key])) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
391
402
|
const subscriberCallback = subscriber.callback;
|
|
392
403
|
subscriberCallback(cachedCollectionWithoutNestedNulls[subscriber.key], subscriber.key);
|
|
393
404
|
continue;
|
|
@@ -435,6 +446,9 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
435
446
|
}
|
|
436
447
|
// If a React component is only interested in a single key then we can set the cached value directly to the state name.
|
|
437
448
|
if (isSubscribedToCollectionMemberKey) {
|
|
449
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollectionWithoutNestedNulls[subscriber.key], previousCollectionWithoutNestedNulls[subscriber.key])) {
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
438
452
|
// However, we only want to update this subscriber if the partial data contains a change.
|
|
439
453
|
// Otherwise, we would update them with a value they already have and trigger an unnecessary re-render.
|
|
440
454
|
const dataFromCollection = partialCollection === null || partialCollection === void 0 ? void 0 : partialCollection[subscriber.key];
|
|
@@ -484,9 +498,9 @@ function keysChanged(collectionKey, partialCollection, notifyRegularSubscibers =
|
|
|
484
498
|
* @example
|
|
485
499
|
* keyChanged(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
486
500
|
*/
|
|
487
|
-
function keyChanged(key,
|
|
501
|
+
function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
|
|
488
502
|
// Add or remove this key from the recentlyAccessedKeys lists
|
|
489
|
-
if (
|
|
503
|
+
if (value !== null) {
|
|
490
504
|
addLastAccessedKey(key);
|
|
491
505
|
}
|
|
492
506
|
else {
|
|
@@ -509,13 +523,13 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
509
523
|
if (isCollectionKey(subscriber.key) && subscriber.waitForCollectionCallback) {
|
|
510
524
|
const cachedCollection = getCachedCollection(subscriber.key);
|
|
511
525
|
const cachedCollectionWithoutNestedNulls = utils_1.default.removeNestedNullValues(cachedCollection);
|
|
512
|
-
cachedCollectionWithoutNestedNulls[key] =
|
|
526
|
+
cachedCollectionWithoutNestedNulls[key] = value;
|
|
513
527
|
subscriber.callback(cachedCollectionWithoutNestedNulls);
|
|
514
528
|
continue;
|
|
515
529
|
}
|
|
516
|
-
const
|
|
530
|
+
const valueWithoutNestedNulls = utils_1.default.removeNestedNullValues(value);
|
|
517
531
|
const subscriberCallback = subscriber.callback;
|
|
518
|
-
subscriberCallback(
|
|
532
|
+
subscriberCallback(valueWithoutNestedNulls, key);
|
|
519
533
|
continue;
|
|
520
534
|
}
|
|
521
535
|
// Subscriber connected via withOnyx() HOC
|
|
@@ -532,7 +546,7 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
532
546
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
533
547
|
const prevWithOnyxData = prevState[subscriber.statePropertyName];
|
|
534
548
|
const newWithOnyxData = {
|
|
535
|
-
[key]: selector(
|
|
549
|
+
[key]: selector(value, subscriber.withOnyxInstance.state),
|
|
536
550
|
};
|
|
537
551
|
const prevDataWithNewData = Object.assign(Object.assign({}, prevWithOnyxData), newWithOnyxData);
|
|
538
552
|
if (!(0, fast_equals_1.deepEqual)(prevWithOnyxData, prevDataWithNewData)) {
|
|
@@ -547,7 +561,7 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
547
561
|
}
|
|
548
562
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
549
563
|
const collection = prevState[subscriber.statePropertyName] || {};
|
|
550
|
-
const newCollection = Object.assign(Object.assign({}, collection), { [key]:
|
|
564
|
+
const newCollection = Object.assign(Object.assign({}, collection), { [key]: value });
|
|
551
565
|
PerformanceUtils.logSetStateCall(subscriber, collection, newCollection, 'keyChanged', key);
|
|
552
566
|
return {
|
|
553
567
|
[subscriber.statePropertyName]: newCollection,
|
|
@@ -559,9 +573,9 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
559
573
|
// returned by the selector and only if the selected data has changed.
|
|
560
574
|
if (selector) {
|
|
561
575
|
subscriber.withOnyxInstance.setStateProxy(() => {
|
|
562
|
-
const
|
|
563
|
-
const newValue = selector(
|
|
564
|
-
if (!(0, fast_equals_1.deepEqual)(
|
|
576
|
+
const prevValue = selector(previousValue, subscriber.withOnyxInstance.state);
|
|
577
|
+
const newValue = selector(value, subscriber.withOnyxInstance.state);
|
|
578
|
+
if (!(0, fast_equals_1.deepEqual)(prevValue, newValue)) {
|
|
565
579
|
return {
|
|
566
580
|
[subscriber.statePropertyName]: newValue,
|
|
567
581
|
};
|
|
@@ -572,17 +586,17 @@ function keyChanged(key, data, prevData, canUpdateSubscriber = () => true, notif
|
|
|
572
586
|
}
|
|
573
587
|
// If we did not match on a collection key then we just set the new data to the state property
|
|
574
588
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
575
|
-
const
|
|
589
|
+
const prevWithOnyxValue = prevState[subscriber.statePropertyName];
|
|
576
590
|
// Avoids triggering unnecessary re-renders when feeding empty objects
|
|
577
|
-
if (utils_1.default.isEmptyObject(
|
|
591
|
+
if (utils_1.default.isEmptyObject(value) && utils_1.default.isEmptyObject(prevWithOnyxValue)) {
|
|
578
592
|
return null;
|
|
579
593
|
}
|
|
580
|
-
if (
|
|
594
|
+
if (prevWithOnyxValue === value) {
|
|
581
595
|
return null;
|
|
582
596
|
}
|
|
583
|
-
PerformanceUtils.logSetStateCall(subscriber,
|
|
597
|
+
PerformanceUtils.logSetStateCall(subscriber, previousValue, value, 'keyChanged', key);
|
|
584
598
|
return {
|
|
585
|
-
[subscriber.statePropertyName]:
|
|
599
|
+
[subscriber.statePropertyName]: value,
|
|
586
600
|
};
|
|
587
601
|
});
|
|
588
602
|
continue;
|
|
@@ -719,9 +733,9 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
719
733
|
* @example
|
|
720
734
|
* scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
|
|
721
735
|
*/
|
|
722
|
-
function scheduleSubscriberUpdate(key, value,
|
|
723
|
-
const promise = Promise.resolve().then(() => keyChanged(key, value,
|
|
724
|
-
batchUpdates(() => keyChanged(key, value,
|
|
736
|
+
function scheduleSubscriberUpdate(key, value, previousValue, canUpdateSubscriber = () => true) {
|
|
737
|
+
const promise = Promise.resolve().then(() => keyChanged(key, value, previousValue, canUpdateSubscriber, true, false));
|
|
738
|
+
batchUpdates(() => keyChanged(key, value, previousValue, canUpdateSubscriber, false, true));
|
|
725
739
|
return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
|
|
726
740
|
}
|
|
727
741
|
/**
|
|
@@ -729,9 +743,9 @@ function scheduleSubscriberUpdate(key, value, prevValue, canUpdateSubscriber = (
|
|
|
729
743
|
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
|
|
730
744
|
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
|
|
731
745
|
*/
|
|
732
|
-
function scheduleNotifyCollectionSubscribers(key, value) {
|
|
733
|
-
const promise = Promise.resolve().then(() => keysChanged(key, value, true, false));
|
|
734
|
-
batchUpdates(() => keysChanged(key, value, false, true));
|
|
746
|
+
function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
747
|
+
const promise = Promise.resolve().then(() => keysChanged(key, value, previousValue, true, false));
|
|
748
|
+
batchUpdates(() => keysChanged(key, value, previousValue, false, true));
|
|
735
749
|
return Promise.all([maybeFlushBatchUpdates(), promise]).then(() => undefined);
|
|
736
750
|
}
|
|
737
751
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,14 @@ import type { Component } from 'react';
|
|
|
2
2
|
import type { Merge } from 'type-fest';
|
|
3
3
|
import type { BuiltIns } from 'type-fest/source/internal';
|
|
4
4
|
import type OnyxUtils from './OnyxUtils';
|
|
5
|
+
/**
|
|
6
|
+
* Utility type that excludes `null` from the type `TValue`.
|
|
7
|
+
*/
|
|
8
|
+
type NonNull<TValue> = TValue extends null ? never : TValue;
|
|
9
|
+
/**
|
|
10
|
+
* Utility type that excludes `undefined` from the type `TValue`.
|
|
11
|
+
*/
|
|
12
|
+
type NonUndefined<TValue> = TValue extends undefined ? never : TValue;
|
|
5
13
|
/**
|
|
6
14
|
* Represents a deeply nested record. It maps keys to values,
|
|
7
15
|
* and those values can either be of type `TValue` or further nested `DeepRecord` instances.
|
|
@@ -126,7 +134,7 @@ type NullableKeyValueMapping = {
|
|
|
126
134
|
*/
|
|
127
135
|
type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>, state: WithOnyxInstanceState<TOnyxProps>) => TReturnType;
|
|
128
136
|
/**
|
|
129
|
-
* Represents a single Onyx entry, that can be either `TOnyxValue` or `null` if it doesn't exist.
|
|
137
|
+
* Represents a single Onyx entry, that can be either `TOnyxValue` or `null` / `undefined` if it doesn't exist.
|
|
130
138
|
*
|
|
131
139
|
* It can be used to specify data retrieved from Onyx e.g. `withOnyx` HOC mappings.
|
|
132
140
|
*
|
|
@@ -153,9 +161,9 @@ type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry
|
|
|
153
161
|
* })(Component);
|
|
154
162
|
* ```
|
|
155
163
|
*/
|
|
156
|
-
type OnyxEntry<TOnyxValue> = TOnyxValue | null;
|
|
164
|
+
type OnyxEntry<TOnyxValue> = TOnyxValue | null | undefined;
|
|
157
165
|
/**
|
|
158
|
-
* Represents an Onyx collection of entries, that can be either a record of `TOnyxValue`s or `null` if it is empty or doesn't exist.
|
|
166
|
+
* Represents an Onyx collection of entries, that can be either a record of `TOnyxValue`s or `null` / `undefined` if it is empty or doesn't exist.
|
|
159
167
|
*
|
|
160
168
|
* It can be used to specify collection data retrieved from Onyx e.g. `withOnyx` HOC mappings.
|
|
161
169
|
*
|
|
@@ -182,7 +190,7 @@ type OnyxEntry<TOnyxValue> = TOnyxValue | null;
|
|
|
182
190
|
* })(Component);
|
|
183
191
|
* ```
|
|
184
192
|
*/
|
|
185
|
-
type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue | null>>;
|
|
193
|
+
type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue | null | undefined>>;
|
|
186
194
|
/** Utility type to extract `TOnyxValue` from `OnyxCollection<TOnyxValue>` */
|
|
187
195
|
type ExtractOnyxCollectionValue<TOnyxCollection> = TOnyxCollection extends NonNullable<OnyxCollection<infer U>> ? U : never;
|
|
188
196
|
type NonTransformableTypes = BuiltIns | ((...args: any[]) => unknown) | Map<unknown, unknown> | Set<unknown> | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | unknown[] | readonly unknown[];
|
|
@@ -247,8 +255,8 @@ type WithOnyxConnectOptions<TKey extends OnyxKey> = {
|
|
|
247
255
|
selector?: Selector<TKey, unknown, unknown>;
|
|
248
256
|
canEvict?: boolean;
|
|
249
257
|
};
|
|
250
|
-
type DefaultConnectCallback<TKey extends OnyxKey> = (value: OnyxEntry<KeyValueMapping[TKey]
|
|
251
|
-
type CollectionConnectCallback<TKey extends OnyxKey> = (value: OnyxCollection<KeyValueMapping[TKey]
|
|
258
|
+
type DefaultConnectCallback<TKey extends OnyxKey> = (value: NonUndefined<OnyxEntry<KeyValueMapping[TKey]>>, key: TKey) => void;
|
|
259
|
+
type CollectionConnectCallback<TKey extends OnyxKey> = (value: NonUndefined<OnyxCollection<KeyValueMapping[TKey]>>) => void;
|
|
252
260
|
/** Represents the callback function used in `Onyx.connect()` method with a regular key. */
|
|
253
261
|
type DefaultConnectOptions<TKey extends OnyxKey> = {
|
|
254
262
|
key: TKey;
|
|
@@ -286,11 +294,11 @@ type OnyxUpdate = {
|
|
|
286
294
|
[TKey in OnyxKey]: {
|
|
287
295
|
onyxMethod: typeof OnyxUtils.METHOD.SET;
|
|
288
296
|
key: TKey;
|
|
289
|
-
value: OnyxEntry<KeyValueMapping[TKey]
|
|
297
|
+
value: NonUndefined<OnyxEntry<KeyValueMapping[TKey]>>;
|
|
290
298
|
} | {
|
|
291
299
|
onyxMethod: typeof OnyxUtils.METHOD.MERGE;
|
|
292
300
|
key: TKey;
|
|
293
|
-
value: OnyxEntry<NullishDeep<KeyValueMapping[TKey]
|
|
301
|
+
value: NonUndefined<OnyxEntry<NullishDeep<KeyValueMapping[TKey]>>>;
|
|
294
302
|
} | {
|
|
295
303
|
onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET;
|
|
296
304
|
key: TKey;
|
|
@@ -334,4 +342,4 @@ type InitOptions = {
|
|
|
334
342
|
/** Enables debugging setState() calls to connected components */
|
|
335
343
|
debugSetState?: boolean;
|
|
336
344
|
};
|
|
337
|
-
export type {
|
|
345
|
+
export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, NullableKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, WithOnyxInstance, WithOnyxInstanceState, };
|
package/dist/useOnyx.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { IsEqual } from 'type-fest';
|
|
2
|
-
import type { CollectionKeyBase, OnyxCollection,
|
|
3
|
-
|
|
2
|
+
import type { CollectionKeyBase, KeyValueMapping, NonNull, OnyxCollection, OnyxEntry, OnyxKey, Selector } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Represents a Onyx value that can be either a single entry or a collection of entries, depending on the `TKey` provided.
|
|
5
|
+
* It's a variation of `OnyxValue` type that is read-only and excludes the `null` type.
|
|
6
|
+
*/
|
|
7
|
+
type UseOnyxValue<TKey extends OnyxKey> = string extends TKey ? unknown : TKey extends CollectionKeyBase ? Readonly<NonNull<OnyxCollection<KeyValueMapping[TKey]>>> : Readonly<NonNull<OnyxEntry<KeyValueMapping[TKey]>>>;
|
|
8
|
+
type BaseUseOnyxOptions = {
|
|
4
9
|
/**
|
|
5
10
|
* Determines if this key in this subscription is safe to be evicted.
|
|
6
11
|
*/
|
|
@@ -13,10 +18,14 @@ type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = {
|
|
|
13
18
|
* If set to true, data will be retrieved from cache during the first render even if there is a pending merge for the key.
|
|
14
19
|
*/
|
|
15
20
|
allowStaleData?: boolean;
|
|
21
|
+
};
|
|
22
|
+
type UseOnyxInitialValueOption<TInitialValue> = {
|
|
16
23
|
/**
|
|
17
24
|
* This value will be returned by the hook on the first render while the data is being read from Onyx.
|
|
18
25
|
*/
|
|
19
|
-
initialValue?:
|
|
26
|
+
initialValue?: TInitialValue;
|
|
27
|
+
};
|
|
28
|
+
type UseOnyxSelectorOption<TKey extends OnyxKey, TReturnValue> = {
|
|
20
29
|
/**
|
|
21
30
|
* This will be used to subscribe to a subset of an Onyx key's data.
|
|
22
31
|
* Using this setting on `useOnyx` can have very positive performance benefits because the component will only re-render
|
|
@@ -26,11 +35,12 @@ type UseOnyxOptions<TKey extends OnyxKey, TReturnValue> = {
|
|
|
26
35
|
selector?: Selector<TKey, unknown, TReturnValue>;
|
|
27
36
|
};
|
|
28
37
|
type FetchStatus = 'loading' | 'loaded';
|
|
29
|
-
type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue,
|
|
38
|
+
type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, UseOnyxValue<TKey>> extends true ? TValue : TKey extends CollectionKeyBase ? Readonly<NonNullable<OnyxCollection<TValue>>> : Readonly<TValue>;
|
|
30
39
|
type ResultMetadata = {
|
|
31
40
|
status: FetchStatus;
|
|
32
41
|
};
|
|
33
42
|
type UseOnyxResult<TKey extends OnyxKey, TValue> = [CachedValue<TKey, TValue>, ResultMetadata];
|
|
34
|
-
declare function useOnyx<TKey extends OnyxKey, TReturnValue =
|
|
43
|
+
declare function useOnyx<TKey extends OnyxKey, TReturnValue = UseOnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<TReturnValue> & Required<UseOnyxSelectorOption<TKey, TReturnValue>>): UseOnyxResult<TKey, TReturnValue>;
|
|
44
|
+
declare function useOnyx<TKey extends OnyxKey, TReturnValue = UseOnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<NoInfer<TReturnValue>>): UseOnyxResult<TKey, TReturnValue>;
|
|
35
45
|
export default useOnyx;
|
|
36
46
|
export type { UseOnyxResult, ResultMetadata, FetchStatus };
|
package/dist/useOnyx.js
CHANGED
|
@@ -21,10 +21,10 @@ function useOnyx(key, options) {
|
|
|
21
21
|
// We initialize it to `undefined` to simulate that we don't have any value from cache yet.
|
|
22
22
|
const cachedValueRef = (0, react_1.useRef)(undefined);
|
|
23
23
|
// Stores the previously result returned by the hook, containing the data from cache and the fetch status.
|
|
24
|
-
// We initialize it to `
|
|
24
|
+
// We initialize it to `undefined` and `loading` fetch status to simulate the initial result when the hook is loading from the cache.
|
|
25
25
|
// However, if `initWithStoredValues` is `true` we set the fetch status to `loaded` since we want to signal that data is ready.
|
|
26
26
|
const resultRef = (0, react_1.useRef)([
|
|
27
|
-
|
|
27
|
+
undefined,
|
|
28
28
|
{
|
|
29
29
|
status: (options === null || options === void 0 ? void 0 : options.initWithStoredValues) === false ? 'loaded' : 'loading',
|
|
30
30
|
},
|
|
@@ -76,8 +76,8 @@ function useOnyx(key, options) {
|
|
|
76
76
|
// and the result to be returned by the hook.
|
|
77
77
|
if (!(0, fast_equals_1.deepEqual)(cachedValueRef.current, newValue)) {
|
|
78
78
|
cachedValueRef.current = newValue;
|
|
79
|
-
// If the new value is `
|
|
80
|
-
resultRef.current = [((_a = cachedValueRef.current) !== null && _a !== void 0 ? _a :
|
|
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' }];
|
|
81
81
|
}
|
|
82
82
|
return resultRef.current;
|
|
83
83
|
}, [key, selectorRef, options === null || options === void 0 ? void 0 : options.allowStaleData, options === null || options === void 0 ? void 0 : options.initialValue]);
|
package/dist/withOnyx.d.ts
CHANGED
|
@@ -125,6 +125,8 @@ type OnyxPropCollectionMapping<TComponentProps, TOnyxProps, TOnyxProp extends ke
|
|
|
125
125
|
}[CollectionKeyBase];
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
+
* @deprecated Use `useOnyx` instead of `withOnyx` whenever possible.
|
|
129
|
+
*
|
|
128
130
|
* This is a higher order component that provides the ability to map a state property directly to
|
|
129
131
|
* something in Onyx (a key/value store). That way, as soon as data in Onyx changes, the state will be set and the view
|
|
130
132
|
* will automatically change to reflect the new data.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.37",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"reassure": "^0.11.0",
|
|
86
86
|
"ts-node": "^10.9.2",
|
|
87
87
|
"type-fest": "^3.12.0",
|
|
88
|
-
"typescript": "^5.
|
|
88
|
+
"typescript": "^5.4.5"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
91
|
"idb-keyval": "^6.2.1",
|