react-native-onyx 2.0.46 → 2.0.48
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 +11 -17
- package/dist/OnyxCache.d.ts +2 -0
- package/dist/OnyxCache.js +6 -2
- package/dist/OnyxUtils.d.ts +7 -7
- package/dist/OnyxUtils.js +50 -40
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +49 -39
- package/dist/useOnyx.d.ts +4 -9
- package/dist/useOnyx.js +15 -11
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js +9 -5
- package/dist/withOnyx/index.js +1 -1
- package/package.json +1 -1
package/dist/Onyx.js
CHANGED
|
@@ -197,9 +197,13 @@ function set(key, value) {
|
|
|
197
197
|
if (OnyxUtils_1.default.hasPendingMergeForKey(key)) {
|
|
198
198
|
delete OnyxUtils_1.default.getMergeQueue()[key];
|
|
199
199
|
}
|
|
200
|
+
// Onyx.set will ignore `undefined` values as inputs, therefore we can return early.
|
|
201
|
+
if (value === undefined) {
|
|
202
|
+
return Promise.resolve();
|
|
203
|
+
}
|
|
200
204
|
const existingValue = OnyxCache_1.default.get(key, false);
|
|
201
205
|
// If the existing value as well as the new value are null, we can return early.
|
|
202
|
-
if (
|
|
206
|
+
if (existingValue === undefined && value === null) {
|
|
203
207
|
return Promise.resolve();
|
|
204
208
|
}
|
|
205
209
|
// Check if the value is compatible with the existing value in the storage
|
|
@@ -244,28 +248,18 @@ function set(key, value) {
|
|
|
244
248
|
* @param data object keyed by ONYXKEYS and the values to set
|
|
245
249
|
*/
|
|
246
250
|
function multiSet(data) {
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
// Therefore, we filter the key value pairs to exclude null values and remove those keys explicitly.
|
|
250
|
-
const removePromises = [];
|
|
251
|
-
const keyValuePairsToUpdate = allKeyValuePairs.filter(([key, value]) => {
|
|
252
|
-
if (value === null) {
|
|
253
|
-
removePromises.push(OnyxUtils_1.default.remove(key));
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
return true;
|
|
257
|
-
});
|
|
258
|
-
const updatePromises = keyValuePairsToUpdate.map(([key, value]) => {
|
|
251
|
+
const keyValuePairsToSet = OnyxUtils_1.default.prepareKeyValuePairsForStorage(data, true);
|
|
252
|
+
const updatePromises = keyValuePairsToSet.map(([key, value]) => {
|
|
259
253
|
const prevValue = OnyxCache_1.default.get(key, false);
|
|
260
254
|
// Update cache and optimistically inform subscribers on the next tick
|
|
261
255
|
OnyxCache_1.default.set(key, value);
|
|
262
256
|
return OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, prevValue);
|
|
263
257
|
});
|
|
264
|
-
return storage_1.default.multiSet(
|
|
258
|
+
return storage_1.default.multiSet(keyValuePairsToSet)
|
|
265
259
|
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, multiSet, data))
|
|
266
260
|
.then(() => {
|
|
267
261
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MULTI_SET, undefined, data);
|
|
268
|
-
return Promise.all(
|
|
262
|
+
return Promise.all(updatePromises);
|
|
269
263
|
})
|
|
270
264
|
.then(() => undefined);
|
|
271
265
|
}
|
|
@@ -515,10 +509,10 @@ function clear(keysToPreserve = []) {
|
|
|
515
509
|
if (!keyValuesToResetAsCollection[collectionKey]) {
|
|
516
510
|
keyValuesToResetAsCollection[collectionKey] = {};
|
|
517
511
|
}
|
|
518
|
-
keyValuesToResetAsCollection[collectionKey][key] = newValue;
|
|
512
|
+
keyValuesToResetAsCollection[collectionKey][key] = newValue !== null && newValue !== void 0 ? newValue : undefined;
|
|
519
513
|
}
|
|
520
514
|
else {
|
|
521
|
-
keyValuesToResetIndividually[key] = newValue;
|
|
515
|
+
keyValuesToResetIndividually[key] = newValue !== null && newValue !== void 0 ? newValue : undefined;
|
|
522
516
|
}
|
|
523
517
|
}
|
|
524
518
|
}
|
package/dist/OnyxCache.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ declare class OnyxCache {
|
|
|
40
40
|
addKey(key: OnyxKey): void;
|
|
41
41
|
/** Used to set keys that are null/undefined in storage without adding null to the storage map */
|
|
42
42
|
addNullishStorageKey(key: OnyxKey): void;
|
|
43
|
+
/** Used to set keys that are null/undefined in storage without adding null to the storage map */
|
|
44
|
+
hasNullishStorageKey(key: OnyxKey): boolean;
|
|
43
45
|
/** Used to clear keys that are null/undefined in cache */
|
|
44
46
|
clearNullishStorageKeys(): void;
|
|
45
47
|
/** Check whether cache has data for the given key */
|
package/dist/OnyxCache.js
CHANGED
|
@@ -20,7 +20,7 @@ class OnyxCache {
|
|
|
20
20
|
this.storageMap = {};
|
|
21
21
|
this.pendingPromises = new Map();
|
|
22
22
|
// bind all public methods to prevent problems with `this`
|
|
23
|
-
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys');
|
|
23
|
+
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'hasNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys');
|
|
24
24
|
}
|
|
25
25
|
/** Get all the storage keys */
|
|
26
26
|
getAllKeys() {
|
|
@@ -50,13 +50,17 @@ class OnyxCache {
|
|
|
50
50
|
addNullishStorageKey(key) {
|
|
51
51
|
this.nullishStorageKeys.add(key);
|
|
52
52
|
}
|
|
53
|
+
/** Used to set keys that are null/undefined in storage without adding null to the storage map */
|
|
54
|
+
hasNullishStorageKey(key) {
|
|
55
|
+
return this.nullishStorageKeys.has(key);
|
|
56
|
+
}
|
|
53
57
|
/** Used to clear keys that are null/undefined in cache */
|
|
54
58
|
clearNullishStorageKeys() {
|
|
55
59
|
this.nullishStorageKeys = new Set();
|
|
56
60
|
}
|
|
57
61
|
/** Check whether cache has data for the given key */
|
|
58
62
|
hasCacheForKey(key) {
|
|
59
|
-
return this.storageMap[key] !== undefined || this.
|
|
63
|
+
return this.storageMap[key] !== undefined || this.hasNullishStorageKey(key);
|
|
60
64
|
}
|
|
61
65
|
/**
|
|
62
66
|
* Get a cached value from storage
|
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ValueOf } from 'type-fest';
|
|
2
2
|
import type Onyx from './Onyx';
|
|
3
|
-
import type { CollectionKey, CollectionKeyBase, DeepRecord, KeyValueMapping, Mapping, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, WithOnyxConnectOptions } from './types';
|
|
3
|
+
import type { CollectionKey, CollectionKeyBase, DeepRecord, KeyValueMapping, Mapping, OnyxCollection, OnyxEntry, OnyxInput, OnyxKey, OnyxValue, WithOnyxConnectOptions } from './types';
|
|
4
4
|
declare const METHOD: {
|
|
5
5
|
readonly SET: "set";
|
|
6
6
|
readonly MERGE: "merge";
|
|
@@ -52,7 +52,7 @@ declare function sendActionToDevTools(method: Exclude<OnyxMethod, typeof METHOD.
|
|
|
52
52
|
declare function maybeFlushBatchUpdates(): Promise<void>;
|
|
53
53
|
declare function batchUpdates(updates: () => void): Promise<void>;
|
|
54
54
|
/** Get some data from the store */
|
|
55
|
-
declare function get(key:
|
|
55
|
+
declare function get<TKey extends OnyxKey, TValue extends OnyxValue<TKey>>(key: TKey): Promise<TValue>;
|
|
56
56
|
/** Returns current key names stored in persisted storage */
|
|
57
57
|
declare function getAllKeys(): Promise<Set<OnyxKey>>;
|
|
58
58
|
/**
|
|
@@ -159,8 +159,8 @@ declare function evictStorageAndRetry<TMethod extends typeof Onyx.set | typeof O
|
|
|
159
159
|
*/
|
|
160
160
|
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean): Promise<void>;
|
|
161
161
|
declare function hasPendingMergeForKey(key: OnyxKey): boolean;
|
|
162
|
-
type RemoveNullValuesOutput<Value extends
|
|
163
|
-
value: Value
|
|
162
|
+
type RemoveNullValuesOutput<Value extends OnyxInput<OnyxKey> | undefined> = {
|
|
163
|
+
value: Value;
|
|
164
164
|
wasRemoved: boolean;
|
|
165
165
|
};
|
|
166
166
|
/**
|
|
@@ -170,7 +170,7 @@ type RemoveNullValuesOutput<Value extends OnyxValue<OnyxKey> | null> = {
|
|
|
170
170
|
*
|
|
171
171
|
* @returns The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
|
|
172
172
|
*/
|
|
173
|
-
declare function removeNullValues<Value extends
|
|
173
|
+
declare function removeNullValues<Value extends OnyxInput<OnyxKey> | undefined>(key: OnyxKey, value: Value, shouldRemoveNestedNulls?: boolean): RemoveNullValuesOutput<Value>;
|
|
174
174
|
/**
|
|
175
175
|
* Storage expects array like: [["@MyApp_user", value_1], ["@MyApp_key", value_2]]
|
|
176
176
|
* This method transforms an object like {'@MyApp_user': myUserValue, '@MyApp_key': myKeyValue}
|
|
@@ -178,13 +178,13 @@ declare function removeNullValues<Value extends OnyxValue<OnyxKey>>(key: OnyxKey
|
|
|
178
178
|
|
|
179
179
|
* @return an array of key - value pairs <[key, value]>
|
|
180
180
|
*/
|
|
181
|
-
declare function prepareKeyValuePairsForStorage(data: Record<OnyxKey,
|
|
181
|
+
declare function prepareKeyValuePairsForStorage(data: Record<OnyxKey, OnyxInput<OnyxKey>>, shouldRemoveNestedNulls: boolean): Array<[OnyxKey, OnyxInput<OnyxKey>]>;
|
|
182
182
|
/**
|
|
183
183
|
* Merges an array of changes with an existing value
|
|
184
184
|
*
|
|
185
185
|
* @param changes Array of changes that should be applied to the existing value
|
|
186
186
|
*/
|
|
187
|
-
declare function applyMerge(existingValue:
|
|
187
|
+
declare function applyMerge<TValue extends OnyxInput<OnyxKey> | undefined, TChange extends OnyxInput<OnyxKey> | undefined>(existingValue: TValue, changes: TChange[], shouldRemoveNestedNulls: boolean): TChange;
|
|
188
188
|
/**
|
|
189
189
|
* Merge user provided default key value pairs.
|
|
190
190
|
*/
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -338,6 +338,10 @@ function getCachedCollection(collectionKey, collectionMemberKeys) {
|
|
|
338
338
|
if (!collectionMemberKeys && !isCollectionMemberKey(collectionKey, key)) {
|
|
339
339
|
return;
|
|
340
340
|
}
|
|
341
|
+
const cachedValue = OnyxCache_1.default.get(key);
|
|
342
|
+
if (cachedValue === undefined && !OnyxCache_1.default.hasNullishStorageKey(key)) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
341
345
|
collection[key] = OnyxCache_1.default.get(key);
|
|
342
346
|
});
|
|
343
347
|
return collection;
|
|
@@ -349,10 +353,6 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
349
353
|
// We prepare the "cached collection" which is the entire collection + the new partial data that
|
|
350
354
|
// was merged in via mergeCollection().
|
|
351
355
|
const cachedCollection = getCachedCollection(collectionKey);
|
|
352
|
-
// If the previous collection equals the new collection then we do not need to notify any subscribers.
|
|
353
|
-
if (partialPreviousCollection !== undefined && (0, fast_equals_1.deepEqual)(cachedCollection, partialPreviousCollection)) {
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
356
|
const previousCollection = partialPreviousCollection !== null && partialPreviousCollection !== void 0 ? partialPreviousCollection : {};
|
|
357
357
|
// We are iterating over all subscribers similar to keyChanged(). However, we are looking for subscribers who are subscribing to either a collection key or
|
|
358
358
|
// 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
|
|
@@ -426,23 +426,27 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
426
426
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
427
427
|
const previousData = prevState[subscriber.statePropertyName];
|
|
428
428
|
const newData = reduceCollectionWithSelector(cachedCollection, collectionSelector, subscriber.withOnyxInstance.state);
|
|
429
|
-
if (
|
|
430
|
-
return
|
|
431
|
-
[subscriber.statePropertyName]: newData,
|
|
432
|
-
};
|
|
429
|
+
if ((0, fast_equals_1.deepEqual)(previousData, newData)) {
|
|
430
|
+
return null;
|
|
433
431
|
}
|
|
434
|
-
return
|
|
432
|
+
return {
|
|
433
|
+
[subscriber.statePropertyName]: newData,
|
|
434
|
+
};
|
|
435
435
|
});
|
|
436
436
|
continue;
|
|
437
437
|
}
|
|
438
438
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
439
439
|
var _a;
|
|
440
|
-
const
|
|
440
|
+
const prevCollection = (_a = prevState === null || prevState === void 0 ? void 0 : prevState[subscriber.statePropertyName]) !== null && _a !== void 0 ? _a : {};
|
|
441
|
+
const finalCollection = (0, clone_1.default)(prevCollection);
|
|
441
442
|
const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
|
|
442
443
|
for (let j = 0; j < dataKeys.length; j++) {
|
|
443
444
|
const dataKey = dataKeys[j];
|
|
444
445
|
finalCollection[dataKey] = cachedCollection[dataKey];
|
|
445
446
|
}
|
|
447
|
+
if ((0, fast_equals_1.deepEqual)(prevCollection, finalCollection)) {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
446
450
|
PerformanceUtils.logSetStateCall(subscriber, prevState === null || prevState === void 0 ? void 0 : prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
|
|
447
451
|
return {
|
|
448
452
|
[subscriber.statePropertyName]: finalCollection,
|
|
@@ -469,29 +473,29 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
469
473
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
470
474
|
const prevData = prevState[subscriber.statePropertyName];
|
|
471
475
|
const newData = selector(cachedCollection[subscriber.key], subscriber.withOnyxInstance.state);
|
|
472
|
-
if (
|
|
473
|
-
|
|
474
|
-
return {
|
|
475
|
-
[subscriber.statePropertyName]: newData,
|
|
476
|
-
};
|
|
476
|
+
if ((0, fast_equals_1.deepEqual)(prevData, newData)) {
|
|
477
|
+
return null;
|
|
477
478
|
}
|
|
478
|
-
|
|
479
|
+
PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keysChanged', collectionKey);
|
|
480
|
+
return {
|
|
481
|
+
[subscriber.statePropertyName]: newData,
|
|
482
|
+
};
|
|
479
483
|
});
|
|
480
484
|
continue;
|
|
481
485
|
}
|
|
482
486
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
483
|
-
const
|
|
484
|
-
const
|
|
487
|
+
const prevData = prevState[subscriber.statePropertyName];
|
|
488
|
+
const newData = cachedCollection[subscriber.key];
|
|
485
489
|
// Avoids triggering unnecessary re-renders when feeding empty objects
|
|
486
|
-
if (utils_1.default.isEmptyObject(
|
|
490
|
+
if (utils_1.default.isEmptyObject(newData) && utils_1.default.isEmptyObject(prevData)) {
|
|
487
491
|
return null;
|
|
488
492
|
}
|
|
489
|
-
if (
|
|
493
|
+
if ((0, fast_equals_1.deepEqual)(prevData, newData)) {
|
|
490
494
|
return null;
|
|
491
495
|
}
|
|
492
|
-
PerformanceUtils.logSetStateCall(subscriber,
|
|
496
|
+
PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keysChanged', collectionKey);
|
|
493
497
|
return {
|
|
494
|
-
[subscriber.statePropertyName]:
|
|
498
|
+
[subscriber.statePropertyName]: newData,
|
|
495
499
|
};
|
|
496
500
|
});
|
|
497
501
|
}
|
|
@@ -553,20 +557,23 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
553
557
|
[key]: selector(value, subscriber.withOnyxInstance.state),
|
|
554
558
|
};
|
|
555
559
|
const prevDataWithNewData = Object.assign(Object.assign({}, prevWithOnyxData), newWithOnyxData);
|
|
556
|
-
if (
|
|
557
|
-
|
|
558
|
-
return {
|
|
559
|
-
[subscriber.statePropertyName]: prevDataWithNewData,
|
|
560
|
-
};
|
|
560
|
+
if ((0, fast_equals_1.deepEqual)(prevWithOnyxData, prevDataWithNewData)) {
|
|
561
|
+
return null;
|
|
561
562
|
}
|
|
562
|
-
|
|
563
|
+
PerformanceUtils.logSetStateCall(subscriber, prevWithOnyxData, newWithOnyxData, 'keyChanged', key);
|
|
564
|
+
return {
|
|
565
|
+
[subscriber.statePropertyName]: prevDataWithNewData,
|
|
566
|
+
};
|
|
563
567
|
});
|
|
564
568
|
continue;
|
|
565
569
|
}
|
|
566
570
|
subscriber.withOnyxInstance.setStateProxy((prevState) => {
|
|
567
|
-
const
|
|
568
|
-
const newCollection = Object.assign(Object.assign({},
|
|
569
|
-
|
|
571
|
+
const prevCollection = prevState[subscriber.statePropertyName] || {};
|
|
572
|
+
const newCollection = Object.assign(Object.assign({}, prevCollection), { [key]: value });
|
|
573
|
+
if ((0, fast_equals_1.deepEqual)(prevCollection, newCollection)) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
PerformanceUtils.logSetStateCall(subscriber, prevCollection, newCollection, 'keyChanged', key);
|
|
570
577
|
return {
|
|
571
578
|
[subscriber.statePropertyName]: newCollection,
|
|
572
579
|
};
|
|
@@ -579,12 +586,12 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
579
586
|
subscriber.withOnyxInstance.setStateProxy(() => {
|
|
580
587
|
const prevValue = selector(previousValue, subscriber.withOnyxInstance.state);
|
|
581
588
|
const newValue = selector(value, subscriber.withOnyxInstance.state);
|
|
582
|
-
if (
|
|
583
|
-
return
|
|
584
|
-
[subscriber.statePropertyName]: newValue,
|
|
585
|
-
};
|
|
589
|
+
if ((0, fast_equals_1.deepEqual)(prevValue, newValue)) {
|
|
590
|
+
return null;
|
|
586
591
|
}
|
|
587
|
-
return
|
|
592
|
+
return {
|
|
593
|
+
[subscriber.statePropertyName]: newValue,
|
|
594
|
+
};
|
|
588
595
|
});
|
|
589
596
|
continue;
|
|
590
597
|
}
|
|
@@ -763,7 +770,7 @@ function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
|
763
770
|
function remove(key) {
|
|
764
771
|
const prevValue = OnyxCache_1.default.get(key, false);
|
|
765
772
|
OnyxCache_1.default.drop(key);
|
|
766
|
-
scheduleSubscriberUpdate(key,
|
|
773
|
+
scheduleSubscriberUpdate(key, undefined, prevValue);
|
|
767
774
|
return storage_1.default.removeItem(key).then(() => undefined);
|
|
768
775
|
}
|
|
769
776
|
function reportStorageQuota() {
|
|
@@ -829,7 +836,10 @@ function hasPendingMergeForKey(key) {
|
|
|
829
836
|
function removeNullValues(key, value, shouldRemoveNestedNulls = true) {
|
|
830
837
|
if (value === null) {
|
|
831
838
|
remove(key);
|
|
832
|
-
return { value
|
|
839
|
+
return { value, wasRemoved: true };
|
|
840
|
+
}
|
|
841
|
+
if (value === undefined) {
|
|
842
|
+
return { value, wasRemoved: false };
|
|
833
843
|
}
|
|
834
844
|
// We can remove all null values in an object by merging it with itself
|
|
835
845
|
// utils.fastMerge recursively goes through the object and removes all null values
|
|
@@ -846,7 +856,7 @@ function removeNullValues(key, value, shouldRemoveNestedNulls = true) {
|
|
|
846
856
|
function prepareKeyValuePairsForStorage(data, shouldRemoveNestedNulls) {
|
|
847
857
|
return Object.entries(data).reduce((pairs, [key, value]) => {
|
|
848
858
|
const { value: valueAfterRemoving, wasRemoved } = removeNullValues(key, value, shouldRemoveNestedNulls);
|
|
849
|
-
if (!wasRemoved) {
|
|
859
|
+
if (!wasRemoved && valueAfterRemoving !== undefined) {
|
|
850
860
|
pairs.push([key, valueAfterRemoving]);
|
|
851
861
|
}
|
|
852
862
|
return pairs;
|
|
@@ -864,7 +874,7 @@ function applyMerge(existingValue, changes, shouldRemoveNestedNulls) {
|
|
|
864
874
|
}
|
|
865
875
|
if (changes.some((change) => change && typeof change === 'object')) {
|
|
866
876
|
// Object values are then merged one after the other
|
|
867
|
-
return changes.reduce((modifiedData, change) => utils_1.default.fastMerge(modifiedData, change, shouldRemoveNestedNulls), existingValue || {});
|
|
877
|
+
return changes.reduce((modifiedData, change) => utils_1.default.fastMerge(modifiedData, change, shouldRemoveNestedNulls), (existingValue || {}));
|
|
868
878
|
}
|
|
869
879
|
// If we have anything else we can't merge it so we'll
|
|
870
880
|
// simply return the last value that was queued
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ConnectOptions, OnyxUpdate } from './Onyx';
|
|
2
2
|
import Onyx from './Onyx';
|
|
3
|
-
import type { CustomTypeOptions, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry,
|
|
3
|
+
import type { CustomTypeOptions, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput } from './types';
|
|
4
4
|
import type { FetchStatus, ResultMetadata, UseOnyxResult } from './useOnyx';
|
|
5
5
|
import useOnyx from './useOnyx';
|
|
6
6
|
import withOnyx from './withOnyx';
|
|
7
7
|
import type { WithOnyxState } from './withOnyx/types';
|
|
8
8
|
export default Onyx;
|
|
9
9
|
export { useOnyx, withOnyx };
|
|
10
|
-
export type { ConnectOptions, CustomTypeOptions, FetchStatus, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry,
|
|
10
|
+
export type { ConnectOptions, CustomTypeOptions, FetchStatus, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, ResultMetadata, Selector, UseOnyxResult, WithOnyxState, };
|
package/dist/types.d.ts
CHANGED
|
@@ -99,30 +99,6 @@ type CollectionKey = `${CollectionKeyBase}${string}`;
|
|
|
99
99
|
* Represents a string union of all Onyx normal and collection keys.
|
|
100
100
|
*/
|
|
101
101
|
type OnyxKey = Key | CollectionKey;
|
|
102
|
-
/**
|
|
103
|
-
* Represents a Onyx value that can be either a single entry or a collection of entries, depending on the `TKey` provided.
|
|
104
|
-
*/
|
|
105
|
-
type OnyxValue<TKey extends OnyxKey> = string extends TKey ? unknown : TKey extends CollectionKeyBase ? OnyxCollection<KeyValueMapping[TKey]> : OnyxEntry<KeyValueMapping[TKey]>;
|
|
106
|
-
/**
|
|
107
|
-
* Represents a mapping of Onyx keys to values, where keys are either normal or collection Onyx keys
|
|
108
|
-
* and values are the corresponding values in Onyx's state.
|
|
109
|
-
*
|
|
110
|
-
* For collection keys, `KeyValueMapping` allows any string to be appended
|
|
111
|
-
* to the key (e.g., 'report_some-id', 'download_some-id').
|
|
112
|
-
*
|
|
113
|
-
* The mapping is derived from the `values` property of the `TypeOptions` type.
|
|
114
|
-
*/
|
|
115
|
-
type KeyValueMapping = {
|
|
116
|
-
[TKey in keyof TypeOptions['values'] as TKey extends CollectionKeyBase ? `${TKey}${string}` : TKey]: TypeOptions['values'][TKey];
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* Represents a mapping object where each `OnyxKey` maps to either a value of its corresponding type in `KeyValueMapping` or `null`.
|
|
120
|
-
*
|
|
121
|
-
* It's very similar to `KeyValueMapping` but this type accepts using `null` as well.
|
|
122
|
-
*/
|
|
123
|
-
type NullableKeyValueMapping = {
|
|
124
|
-
[TKey in OnyxKey]: NonUndefined<OnyxValue<TKey>> | null;
|
|
125
|
-
};
|
|
126
102
|
/**
|
|
127
103
|
* Represents a selector function type which operates based on the provided `TKey` and `ReturnType`.
|
|
128
104
|
*
|
|
@@ -134,7 +110,7 @@ type NullableKeyValueMapping = {
|
|
|
134
110
|
*/
|
|
135
111
|
type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry<KeyValueMapping[TKey]>, state?: WithOnyxState<TOnyxProps>) => TReturnType;
|
|
136
112
|
/**
|
|
137
|
-
* Represents a single Onyx entry, that can be either `TOnyxValue` or `
|
|
113
|
+
* Represents a single Onyx entry, that can be either `TOnyxValue` or `undefined` if it doesn't exist.
|
|
138
114
|
*
|
|
139
115
|
* It can be used to specify data retrieved from Onyx e.g. `withOnyx` HOC mappings.
|
|
140
116
|
*
|
|
@@ -163,13 +139,7 @@ type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry
|
|
|
163
139
|
*/
|
|
164
140
|
type OnyxEntry<TOnyxValue> = TOnyxValue | undefined;
|
|
165
141
|
/**
|
|
166
|
-
* Represents an
|
|
167
|
-
* Setting a key to `null` will remove the key from the store.
|
|
168
|
-
* `undefined` is not allowed for setting values, because it will have no effect on the data.
|
|
169
|
-
*/
|
|
170
|
-
type OnyxInput<TOnyxValue> = TOnyxValue | null;
|
|
171
|
-
/**
|
|
172
|
-
* 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.
|
|
142
|
+
* Represents an Onyx collection of entries, that can be either a record of `TOnyxValue`s or `undefined` if it is empty or doesn't exist.
|
|
173
143
|
*
|
|
174
144
|
* It can be used to specify collection data retrieved from Onyx e.g. `withOnyx` HOC mappings.
|
|
175
145
|
*
|
|
@@ -197,6 +167,22 @@ type OnyxInput<TOnyxValue> = TOnyxValue | null;
|
|
|
197
167
|
* ```
|
|
198
168
|
*/
|
|
199
169
|
type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue | undefined>>;
|
|
170
|
+
/**
|
|
171
|
+
* Represents a mapping of Onyx keys to values, where keys are either normal or collection Onyx keys
|
|
172
|
+
* and values are the corresponding values in Onyx's state.
|
|
173
|
+
*
|
|
174
|
+
* For collection keys, `KeyValueMapping` allows any string to be appended
|
|
175
|
+
* to the key (e.g., 'report_some-id', 'download_some-id').
|
|
176
|
+
*
|
|
177
|
+
* The mapping is derived from the `values` property of the `TypeOptions` type.
|
|
178
|
+
*/
|
|
179
|
+
type KeyValueMapping = {
|
|
180
|
+
[TKey in keyof TypeOptions['values'] as TKey extends CollectionKeyBase ? `${TKey}${string}` : TKey]: TypeOptions['values'][TKey];
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Represents a Onyx value that can be either a single entry or a collection of entries, depending on the `TKey` provided.
|
|
184
|
+
*/
|
|
185
|
+
type OnyxValue<TKey extends OnyxKey> = string extends TKey ? unknown : TKey extends CollectionKeyBase ? OnyxCollection<KeyValueMapping[TKey]> : OnyxEntry<KeyValueMapping[TKey]>;
|
|
200
186
|
/** Utility type to extract `TOnyxValue` from `OnyxCollection<TOnyxValue>` */
|
|
201
187
|
type ExtractOnyxCollectionValue<TOnyxCollection> = TOnyxCollection extends NonNullable<OnyxCollection<infer U>> ? U : never;
|
|
202
188
|
type NonTransformableTypes = BuiltIns | ((...args: any[]) => unknown) | Map<unknown, unknown> | Set<unknown> | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | unknown[] | readonly unknown[];
|
|
@@ -251,7 +237,7 @@ type WithOnyxConnectOptions<TKey extends OnyxKey> = {
|
|
|
251
237
|
selector?: Selector<TKey, unknown, unknown>;
|
|
252
238
|
canEvict?: boolean;
|
|
253
239
|
};
|
|
254
|
-
type DefaultConnectCallback<TKey extends OnyxKey> = (value:
|
|
240
|
+
type DefaultConnectCallback<TKey extends OnyxKey> = (value: OnyxEntry<KeyValueMapping[TKey]>, key: TKey) => void;
|
|
255
241
|
type CollectionConnectCallback<TKey extends OnyxKey> = (value: NonUndefined<OnyxCollection<KeyValueMapping[TKey]>>) => void;
|
|
256
242
|
/** Represents the callback function used in `Onyx.connect()` method with a regular key. */
|
|
257
243
|
type DefaultConnectOptions<TKey extends OnyxKey> = {
|
|
@@ -282,22 +268,46 @@ type ConnectOptions<TKey extends OnyxKey> = (CollectionConnectOptions<TKey> | De
|
|
|
282
268
|
type Mapping<TKey extends OnyxKey> = ConnectOptions<TKey> & {
|
|
283
269
|
connectionID: number;
|
|
284
270
|
};
|
|
271
|
+
/**
|
|
272
|
+
* Represents a single Onyx input value, that can be either `TOnyxValue` or `null` if the key should be deleted.
|
|
273
|
+
* This type is used for data passed to Onyx e.g. in `Onyx.merge` and `Onyx.set`.
|
|
274
|
+
*/
|
|
275
|
+
type OnyxInputValue<TOnyxValue> = TOnyxValue | null;
|
|
276
|
+
/**
|
|
277
|
+
* Represents an Onyx collection input, that can be either a record of `TOnyxValue`s or `null` if the key should be deleted.
|
|
278
|
+
*/
|
|
279
|
+
type OnyxCollectionInputValue<TOnyxValue> = OnyxInputValue<Record<string, TOnyxValue | null>>;
|
|
280
|
+
/**
|
|
281
|
+
* Represents an input value that can be passed to Onyx methods, that can be either `TOnyxValue` or `null`.
|
|
282
|
+
* Setting a key to `null` will remove the key from the store.
|
|
283
|
+
* `undefined` is not allowed for setting values, because it will have no effect on the data.
|
|
284
|
+
*/
|
|
285
|
+
type OnyxInput<TKey extends OnyxKey> = OnyxInputValue<NullishDeep<KeyValueMapping[TKey]>>;
|
|
286
|
+
/**
|
|
287
|
+
* Represents a mapping object where each `OnyxKey` maps to either a value of its corresponding type in `KeyValueMapping` or `null`.
|
|
288
|
+
*
|
|
289
|
+
* It's very similar to `KeyValueMapping` but this type is used for inputs to Onyx
|
|
290
|
+
* (set, merge, mergeCollection) and therefore accepts using `null` to remove a key from Onyx.
|
|
291
|
+
*/
|
|
292
|
+
type OnyxInputKeyValueMapping = {
|
|
293
|
+
[TKey in OnyxKey]: OnyxInput<TKey>;
|
|
294
|
+
};
|
|
285
295
|
/**
|
|
286
296
|
* This represents the value that can be passed to `Onyx.set` and to `Onyx.update` with the method "SET"
|
|
287
297
|
*/
|
|
288
|
-
type OnyxSetInput<TKey extends OnyxKey> = OnyxInput<
|
|
298
|
+
type OnyxSetInput<TKey extends OnyxKey> = OnyxInput<TKey>;
|
|
289
299
|
/**
|
|
290
300
|
* This represents the value that can be passed to `Onyx.multiSet` and to `Onyx.update` with the method "MULTI_SET"
|
|
291
301
|
*/
|
|
292
|
-
type OnyxMultiSetInput = Partial<
|
|
302
|
+
type OnyxMultiSetInput = Partial<OnyxInputKeyValueMapping>;
|
|
293
303
|
/**
|
|
294
304
|
* This represents the value that can be passed to `Onyx.merge` and to `Onyx.update` with the method "MERGE"
|
|
295
305
|
*/
|
|
296
|
-
type OnyxMergeInput<TKey extends OnyxKey> = OnyxInput<
|
|
306
|
+
type OnyxMergeInput<TKey extends OnyxKey> = OnyxInput<TKey>;
|
|
297
307
|
/**
|
|
298
308
|
* This represents the value that can be passed to `Onyx.merge` and to `Onyx.update` with the method "MERGE"
|
|
299
309
|
*/
|
|
300
|
-
type OnyxMergeCollectionInput<TKey extends OnyxKey, TMap = object> = Collection<TKey,
|
|
310
|
+
type OnyxMergeCollectionInput<TKey extends OnyxKey, TMap = object> = Collection<TKey, NonNullable<OnyxInput<TKey>>, TMap>;
|
|
301
311
|
/**
|
|
302
312
|
* Represents different kinds of updates that can be passed to `Onyx.update()` method. It is a discriminated union of
|
|
303
313
|
* different update methods (`SET`, `MERGE`, `MERGE_COLLECTION`), each with their own key and value structure.
|
|
@@ -334,7 +344,7 @@ type InitOptions = {
|
|
|
334
344
|
/** `ONYXKEYS` constants object */
|
|
335
345
|
keys?: DeepRecord<string, OnyxKey>;
|
|
336
346
|
/** initial data to set when `init()` and `clear()` is called */
|
|
337
|
-
initialKeyStates?: Partial<
|
|
347
|
+
initialKeyStates?: Partial<OnyxInputKeyValueMapping>;
|
|
338
348
|
/**
|
|
339
349
|
* This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged
|
|
340
350
|
* as "safe" for removal. Any components subscribing to these keys must also implement a canEvict option. See the README for more info.
|
|
@@ -355,4 +365,4 @@ type InitOptions = {
|
|
|
355
365
|
debugSetState?: boolean;
|
|
356
366
|
};
|
|
357
367
|
type GenericFunction = (...args: any[]) => any;
|
|
358
|
-
export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined,
|
|
368
|
+
export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, OnyxInputKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, };
|
package/dist/useOnyx.d.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { IsEqual } from 'type-fest';
|
|
2
|
-
import type { CollectionKeyBase,
|
|
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 ? NonNull<OnyxCollection<KeyValueMapping[TKey]>> : NonNull<OnyxEntry<KeyValueMapping[TKey]>>;
|
|
2
|
+
import type { CollectionKeyBase, OnyxCollection, OnyxKey, OnyxValue, Selector } from './types';
|
|
8
3
|
type BaseUseOnyxOptions = {
|
|
9
4
|
/**
|
|
10
5
|
* Determines if this key in this subscription is safe to be evicted.
|
|
@@ -35,12 +30,12 @@ type UseOnyxSelectorOption<TKey extends OnyxKey, TReturnValue> = {
|
|
|
35
30
|
selector?: Selector<TKey, unknown, TReturnValue>;
|
|
36
31
|
};
|
|
37
32
|
type FetchStatus = 'loading' | 'loaded';
|
|
38
|
-
type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue,
|
|
33
|
+
type CachedValue<TKey extends OnyxKey, TValue> = IsEqual<TValue, OnyxValue<TKey>> extends true ? TValue : TKey extends CollectionKeyBase ? NonNullable<OnyxCollection<TValue>> : TValue;
|
|
39
34
|
type ResultMetadata = {
|
|
40
35
|
status: FetchStatus;
|
|
41
36
|
};
|
|
42
37
|
type UseOnyxResult<TKey extends OnyxKey, TValue> = [CachedValue<TKey, TValue>, ResultMetadata];
|
|
43
|
-
declare function useOnyx<TKey extends OnyxKey, TReturnValue =
|
|
44
|
-
declare function useOnyx<TKey extends OnyxKey, TReturnValue =
|
|
38
|
+
declare function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<TReturnValue> & Required<UseOnyxSelectorOption<TKey, TReturnValue>>): UseOnyxResult<TKey, TReturnValue>;
|
|
39
|
+
declare function useOnyx<TKey extends OnyxKey, TReturnValue = OnyxValue<TKey>>(key: TKey, options?: BaseUseOnyxOptions & UseOnyxInitialValueOption<NoInfer<TReturnValue>>): UseOnyxResult<TKey, TReturnValue>;
|
|
45
40
|
export default useOnyx;
|
|
46
41
|
export type { UseOnyxResult, ResultMetadata, FetchStatus };
|
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
|
-
|
|
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 `
|
|
22
|
-
const cachedValueRef = (0, react_1.useRef)(
|
|
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
|
|
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
|
|
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 &&
|
|
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
|
-
|
|
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
|
-
|
|
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/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OnyxInput, OnyxKey } from './types';
|
|
2
2
|
type EmptyObject = Record<string, never>;
|
|
3
3
|
type EmptyValue = EmptyObject | null | undefined;
|
|
4
4
|
/** Checks whether the given object is an object and not null/undefined. */
|
|
@@ -10,9 +10,9 @@ declare function isEmptyObject<T>(obj: T | EmptyValue): obj is EmptyValue;
|
|
|
10
10
|
* On native, when merging an existing value with new changes, SQLite will use JSON_PATCH, which removes top-level nullish values.
|
|
11
11
|
* To be consistent with the behaviour for merge, we'll also want to remove null values for "set" operations.
|
|
12
12
|
*/
|
|
13
|
-
declare function fastMerge<
|
|
13
|
+
declare function fastMerge<TValue>(target: TValue, source: TValue, shouldRemoveNestedNulls?: boolean): TValue;
|
|
14
14
|
/** Deep removes the nested null values from the given value. */
|
|
15
|
-
declare function removeNestedNullValues<TValue extends
|
|
15
|
+
declare function removeNestedNullValues<TValue extends OnyxInput<OnyxKey> | null>(value: TValue): TValue;
|
|
16
16
|
/** Formats the action name by uppercasing and adding the key if provided. */
|
|
17
17
|
declare function formatActionName(method: string, key?: OnyxKey): string;
|
|
18
18
|
/** validate that the update and the existing value are compatible */
|
package/dist/utils.js
CHANGED
|
@@ -22,19 +22,23 @@ function isMergeableObject(value) {
|
|
|
22
22
|
*/
|
|
23
23
|
function mergeObject(target, source, shouldRemoveNestedNulls = true) {
|
|
24
24
|
const destination = {};
|
|
25
|
+
const targetObject = isMergeableObject(target) ? target : undefined;
|
|
25
26
|
// First we want to copy over all keys from the target into the destination object,
|
|
26
27
|
// in case "target" is a mergable object.
|
|
27
28
|
// If "shouldRemoveNestedNulls" is true, we want to remove null values from the merged object
|
|
28
29
|
// and therefore we need to omit keys where either the source or target value is null.
|
|
29
|
-
if (
|
|
30
|
-
const targetKeys = Object.keys(
|
|
30
|
+
if (targetObject) {
|
|
31
|
+
const targetKeys = Object.keys(targetObject);
|
|
31
32
|
for (let i = 0; i < targetKeys.length; ++i) {
|
|
32
33
|
const key = targetKeys[i];
|
|
33
34
|
const sourceValue = source === null || source === void 0 ? void 0 : source[key];
|
|
34
|
-
const targetValue =
|
|
35
|
+
const targetValue = targetObject === null || targetObject === void 0 ? void 0 : targetObject[key];
|
|
35
36
|
// If "shouldRemoveNestedNulls" is true, we want to remove null values from the merged object.
|
|
36
37
|
// Therefore, if either target or source value is null, we want to prevent the key from being set.
|
|
37
|
-
|
|
38
|
+
// targetValue should techincally never be "undefined", because it will always be a value from cache or storage
|
|
39
|
+
// and we never set "undefined" there. Still, if there targetValue is undefined we don't want to set
|
|
40
|
+
// the key explicitly to prevent loose undefined values in objects in cache and storage.
|
|
41
|
+
const isSourceOrTargetNull = targetValue === undefined || targetValue === null || sourceValue === null;
|
|
38
42
|
const shouldOmitTargetKey = shouldRemoveNestedNulls && isSourceOrTargetNull;
|
|
39
43
|
if (!shouldOmitTargetKey) {
|
|
40
44
|
destination[key] = targetValue;
|
|
@@ -46,7 +50,7 @@ function mergeObject(target, source, shouldRemoveNestedNulls = true) {
|
|
|
46
50
|
for (let i = 0; i < sourceKeys.length; ++i) {
|
|
47
51
|
const key = sourceKeys[i];
|
|
48
52
|
const sourceValue = source === null || source === void 0 ? void 0 : source[key];
|
|
49
|
-
const targetValue =
|
|
53
|
+
const targetValue = targetObject === null || targetObject === void 0 ? void 0 : targetObject[key];
|
|
50
54
|
// If undefined is passed as the source value for a key, we want to generally ignore it.
|
|
51
55
|
// If "shouldRemoveNestedNulls" is set to true and the source value is null,
|
|
52
56
|
// we don't want to set/merge the source value into the merged object.
|
package/dist/withOnyx/index.js
CHANGED
|
@@ -207,7 +207,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
207
207
|
}
|
|
208
208
|
this.tempState[statePropertyName] = val;
|
|
209
209
|
// If some key does not have a value yet, do not update the state yet
|
|
210
|
-
const tempStateIsMissingKey = requiredKeysForInit.some((key) => { var _a; return ((_a = this.tempState)
|
|
210
|
+
const tempStateIsMissingKey = requiredKeysForInit.some((key) => { var _a; return !(key in ((_a = this.tempState) !== null && _a !== void 0 ? _a : {})); });
|
|
211
211
|
if (tempStateIsMissingKey) {
|
|
212
212
|
return;
|
|
213
213
|
}
|