react-native-onyx 2.0.42 → 2.0.44
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 +5 -5
- package/dist/Onyx.js +61 -26
- package/dist/OnyxCache.d.ts +24 -18
- package/dist/OnyxCache.js +53 -31
- package/dist/OnyxUtils.d.ts +8 -8
- package/dist/OnyxUtils.js +40 -34
- package/dist/index.d.ts +2 -2
- package/dist/storage/providers/IDBKeyValProvider.js +24 -3
- package/dist/types.d.ts +33 -11
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -1
- package/dist/withOnyx/index.js +16 -11
- package/dist/withOnyx/types.d.ts +2 -2
- package/package.json +1 -1
package/dist/Onyx.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Logger from './Logger';
|
|
2
|
-
import type {
|
|
2
|
+
import type { CollectionKeyBase, ConnectOptions, InitOptions, Mapping, OnyxKey, OnyxMergeCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetInput, 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:
|
|
48
|
+
declare function set<TKey extends OnyxKey>(key: TKey, value: OnyxSetInput<TKey>): Promise<void>;
|
|
49
49
|
/**
|
|
50
50
|
* Sets multiple keys and values
|
|
51
51
|
*
|
|
@@ -53,7 +53,7 @@ declare function set<TKey extends OnyxKey>(key: TKey, value: NonUndefined<OnyxEn
|
|
|
53
53
|
*
|
|
54
54
|
* @param data object keyed by ONYXKEYS and the values to set
|
|
55
55
|
*/
|
|
56
|
-
declare function multiSet(data:
|
|
56
|
+
declare function multiSet(data: OnyxMultiSetInput): Promise<void>;
|
|
57
57
|
/**
|
|
58
58
|
* Merge a new value into an existing value at a key.
|
|
59
59
|
*
|
|
@@ -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:
|
|
73
|
+
declare function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>): Promise<void>;
|
|
74
74
|
/**
|
|
75
75
|
* Merges a collection based on their keys
|
|
76
76
|
*
|
|
@@ -84,7 +84,7 @@ declare function merge<TKey extends OnyxKey>(key: TKey, changes: NonUndefined<On
|
|
|
84
84
|
* @param collectionKey e.g. `ONYXKEYS.COLLECTION.REPORT`
|
|
85
85
|
* @param collection Object collection keyed by individual collection member keys and values
|
|
86
86
|
*/
|
|
87
|
-
declare function mergeCollection<TKey extends CollectionKeyBase, TMap>(collectionKey: TKey, collection:
|
|
87
|
+
declare function mergeCollection<TKey extends CollectionKeyBase, TMap>(collectionKey: TKey, collection: OnyxMergeCollectionInput<TKey, TMap>): Promise<void>;
|
|
88
88
|
/**
|
|
89
89
|
* Clear out all the data in the store
|
|
90
90
|
*
|
package/dist/Onyx.js
CHANGED
|
@@ -47,7 +47,7 @@ function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCach
|
|
|
47
47
|
storage_1.default.init();
|
|
48
48
|
if (shouldSyncMultipleInstances) {
|
|
49
49
|
(_a = storage_1.default.keepInstancesSync) === null || _a === void 0 ? void 0 : _a.call(storage_1.default, (key, value) => {
|
|
50
|
-
const prevValue = OnyxCache_1.default.
|
|
50
|
+
const prevValue = OnyxCache_1.default.get(key, false);
|
|
51
51
|
OnyxCache_1.default.set(key, value);
|
|
52
52
|
OnyxUtils_1.default.keyChanged(key, value, prevValue);
|
|
53
53
|
});
|
|
@@ -106,7 +106,7 @@ function connect(connectOptions) {
|
|
|
106
106
|
// Performance improvement
|
|
107
107
|
// If the mapping is connected to an onyx key that is not a collection
|
|
108
108
|
// we can skip the call to getAllKeys() and return an array with a single item
|
|
109
|
-
if (Boolean(mapping.key) && typeof mapping.key === 'string' && !mapping.key.endsWith('_') && OnyxCache_1.default.
|
|
109
|
+
if (Boolean(mapping.key) && typeof mapping.key === 'string' && !mapping.key.endsWith('_') && OnyxCache_1.default.getAllKeys().has(mapping.key)) {
|
|
110
110
|
return new Set([mapping.key]);
|
|
111
111
|
}
|
|
112
112
|
return OnyxUtils_1.default.getAllKeys();
|
|
@@ -122,9 +122,9 @@ function connect(connectOptions) {
|
|
|
122
122
|
// component. This null value will be filtered out so that the connected component can utilize defaultProps.
|
|
123
123
|
if (matchingKeys.length === 0) {
|
|
124
124
|
if (mapping.key && !OnyxUtils_1.default.isCollectionKey(mapping.key)) {
|
|
125
|
-
OnyxCache_1.default.
|
|
125
|
+
OnyxCache_1.default.addNullishStorageKey(mapping.key);
|
|
126
126
|
}
|
|
127
|
-
// Here we cannot use batching because the
|
|
127
|
+
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
|
|
128
128
|
// or they will be undefined.
|
|
129
129
|
OnyxUtils_1.default.sendDataToConnection(mapping, null, undefined, false);
|
|
130
130
|
return;
|
|
@@ -192,8 +192,17 @@ function disconnect(connectionID, keyToRemoveFromEvictionBlocklist) {
|
|
|
192
192
|
* @param value value to store
|
|
193
193
|
*/
|
|
194
194
|
function set(key, value) {
|
|
195
|
-
//
|
|
196
|
-
|
|
195
|
+
// When we use Onyx.set to set a key we want to clear the current delta changes from Onyx.merge that were queued
|
|
196
|
+
// before the value was set. If Onyx.merge is currently reading the old value from storage, it will then not apply the changes.
|
|
197
|
+
if (OnyxUtils_1.default.hasPendingMergeForKey(key)) {
|
|
198
|
+
delete OnyxUtils_1.default.getMergeQueue()[key];
|
|
199
|
+
}
|
|
200
|
+
const existingValue = OnyxCache_1.default.get(key, false);
|
|
201
|
+
// If the existing value as well as the new value are null, we can return early.
|
|
202
|
+
if (value === null && existingValue === null) {
|
|
203
|
+
return Promise.resolve();
|
|
204
|
+
}
|
|
205
|
+
// Check if the value is compatible with the existing value in the storage
|
|
197
206
|
const { isCompatible, existingValueType, newValueType } = utils_1.default.checkCompatibilityWithExistingValue(value, existingValue);
|
|
198
207
|
if (!isCompatible) {
|
|
199
208
|
Logger.logAlert(logMessages_1.default.incompatibleUpdateAlert(key, 'set', existingValueType, newValueType));
|
|
@@ -201,17 +210,23 @@ function set(key, value) {
|
|
|
201
210
|
}
|
|
202
211
|
// If the value is null, we remove the key from storage
|
|
203
212
|
const { value: valueAfterRemoving, wasRemoved } = OnyxUtils_1.default.removeNullValues(key, value);
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
213
|
+
const logSetCall = (hasChanged = true) => {
|
|
214
|
+
// Logging properties only since values could be sensitive things we don't want to log
|
|
215
|
+
Logger.logInfo(`set called for key: ${key}${underscore_1.default.isObject(value) ? ` properties: ${underscore_1.default.keys(value).join(',')}` : ''} hasChanged: ${hasChanged}`);
|
|
216
|
+
};
|
|
217
|
+
// Calling "OnyxUtils.removeNullValues" removes the key from storage and cache and updates the subscriber.
|
|
218
|
+
// Therefore, we don't need to further broadcast and update the value so we can return early.
|
|
219
|
+
if (wasRemoved) {
|
|
220
|
+
logSetCall();
|
|
221
|
+
return Promise.resolve();
|
|
207
222
|
}
|
|
223
|
+
const valueWithoutNullValues = valueAfterRemoving;
|
|
208
224
|
const hasChanged = OnyxCache_1.default.hasValueChanged(key, valueWithoutNullValues);
|
|
209
|
-
|
|
210
|
-
Logger.logInfo(`set called for key: ${key}${underscore_1.default.isObject(value) ? ` properties: ${underscore_1.default.keys(value).join(',')}` : ''} hasChanged: ${hasChanged}`);
|
|
225
|
+
logSetCall(hasChanged);
|
|
211
226
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
212
|
-
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, valueWithoutNullValues, hasChanged
|
|
227
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, valueWithoutNullValues, hasChanged);
|
|
213
228
|
// If the value has not changed or the key got removed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
214
|
-
if (!hasChanged
|
|
229
|
+
if (!hasChanged) {
|
|
215
230
|
return updatePromise;
|
|
216
231
|
}
|
|
217
232
|
return storage_1.default.setItem(key, valueWithoutNullValues)
|
|
@@ -229,18 +244,28 @@ function set(key, value) {
|
|
|
229
244
|
* @param data object keyed by ONYXKEYS and the values to set
|
|
230
245
|
*/
|
|
231
246
|
function multiSet(data) {
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
247
|
+
const allKeyValuePairs = OnyxUtils_1.default.prepareKeyValuePairsForStorage(data, true);
|
|
248
|
+
// When a key is set to null, we need to remove the remove the key from storage using "OnyxUtils.remove".
|
|
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]) => {
|
|
259
|
+
const prevValue = OnyxCache_1.default.get(key, false);
|
|
235
260
|
// Update cache and optimistically inform subscribers on the next tick
|
|
236
261
|
OnyxCache_1.default.set(key, value);
|
|
237
262
|
return OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, prevValue);
|
|
238
263
|
});
|
|
239
|
-
return storage_1.default.multiSet(
|
|
264
|
+
return storage_1.default.multiSet(allKeyValuePairs)
|
|
240
265
|
.catch((error) => OnyxUtils_1.default.evictStorageAndRetry(error, multiSet, data))
|
|
241
266
|
.then(() => {
|
|
242
267
|
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MULTI_SET, undefined, data);
|
|
243
|
-
return Promise.all(updatePromises);
|
|
268
|
+
return Promise.all([removePromises, updatePromises]);
|
|
244
269
|
})
|
|
245
270
|
.then(() => undefined);
|
|
246
271
|
}
|
|
@@ -278,7 +303,7 @@ function merge(key, changes) {
|
|
|
278
303
|
mergeQueuePromise[key] = OnyxUtils_1.default.get(key).then((existingValue) => {
|
|
279
304
|
// Calls to Onyx.set after a merge will terminate the current merge process and clear the merge queue
|
|
280
305
|
if (mergeQueue[key] == null) {
|
|
281
|
-
return
|
|
306
|
+
return Promise.resolve();
|
|
282
307
|
}
|
|
283
308
|
try {
|
|
284
309
|
// We first only merge the changes, so we can provide these to the native implementation (SQLite uses only delta changes in "JSON_PATCH" to merge)
|
|
@@ -291,7 +316,7 @@ function merge(key, changes) {
|
|
|
291
316
|
return isCompatible;
|
|
292
317
|
});
|
|
293
318
|
if (!validChanges.length) {
|
|
294
|
-
return
|
|
319
|
+
return Promise.resolve();
|
|
295
320
|
}
|
|
296
321
|
const batchedDeltaChanges = OnyxUtils_1.default.applyMerge(undefined, validChanges, false);
|
|
297
322
|
// Case (1): When there is no existing value in storage, we want to set the value instead of merge it.
|
|
@@ -301,8 +326,18 @@ function merge(key, changes) {
|
|
|
301
326
|
// Clean up the write queue, so we don't apply these changes again
|
|
302
327
|
delete mergeQueue[key];
|
|
303
328
|
delete mergeQueuePromise[key];
|
|
329
|
+
const logMergeCall = (hasChanged = true) => {
|
|
330
|
+
// Logging properties only since values could be sensitive things we don't want to log
|
|
331
|
+
Logger.logInfo(`merge called for key: ${key}${underscore_1.default.isObject(batchedDeltaChanges) ? ` properties: ${underscore_1.default.keys(batchedDeltaChanges).join(',')}` : ''} hasChanged: ${hasChanged}`);
|
|
332
|
+
};
|
|
304
333
|
// If the batched changes equal null, we want to remove the key from storage, to reduce storage size
|
|
305
334
|
const { wasRemoved } = OnyxUtils_1.default.removeNullValues(key, batchedDeltaChanges);
|
|
335
|
+
// Calling "OnyxUtils.removeNullValues" removes the key from storage and cache and updates the subscriber.
|
|
336
|
+
// Therefore, we don't need to further broadcast and update the value so we can return early.
|
|
337
|
+
if (wasRemoved) {
|
|
338
|
+
logMergeCall();
|
|
339
|
+
return Promise.resolve();
|
|
340
|
+
}
|
|
306
341
|
// For providers that can't handle delta changes, we need to merge the batched changes with the existing value beforehand.
|
|
307
342
|
// The "preMergedValue" will be directly "set" in storage instead of being merged
|
|
308
343
|
// Therefore we merge the batched changes with the existing value to get the final merged value that will be stored.
|
|
@@ -310,12 +345,11 @@ function merge(key, changes) {
|
|
|
310
345
|
const preMergedValue = OnyxUtils_1.default.applyMerge(shouldSetValue ? undefined : existingValue, [batchedDeltaChanges], true);
|
|
311
346
|
// In cache, we don't want to remove the key if it's null to improve performance and speed up the next merge.
|
|
312
347
|
const hasChanged = OnyxCache_1.default.hasValueChanged(key, preMergedValue);
|
|
313
|
-
|
|
314
|
-
Logger.logInfo(`merge called for key: ${key}${underscore_1.default.isObject(batchedDeltaChanges) ? ` properties: ${underscore_1.default.keys(batchedDeltaChanges).join(',')}` : ''} hasChanged: ${hasChanged}`);
|
|
348
|
+
logMergeCall(hasChanged);
|
|
315
349
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
316
|
-
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, preMergedValue, hasChanged
|
|
350
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, preMergedValue, hasChanged);
|
|
317
351
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
318
|
-
if (!hasChanged
|
|
352
|
+
if (!hasChanged) {
|
|
319
353
|
return updatePromise;
|
|
320
354
|
}
|
|
321
355
|
return storage_1.default.mergeItem(key, batchedDeltaChanges, preMergedValue, shouldSetValue).then(() => {
|
|
@@ -453,6 +487,7 @@ function mergeCollection(collectionKey, collection) {
|
|
|
453
487
|
function clear(keysToPreserve = []) {
|
|
454
488
|
return OnyxUtils_1.default.getAllKeys()
|
|
455
489
|
.then((keys) => {
|
|
490
|
+
OnyxCache_1.default.clearNullishStorageKeys();
|
|
456
491
|
const keysToBeClearedFromStorage = [];
|
|
457
492
|
const keyValuesToResetAsCollection = {};
|
|
458
493
|
const keyValuesToResetIndividually = {};
|
|
@@ -471,7 +506,7 @@ function clear(keysToPreserve = []) {
|
|
|
471
506
|
// 2. Figure out whether it is a collection key or not,
|
|
472
507
|
// since collection key subscribers need to be updated differently
|
|
473
508
|
if (!isKeyToPreserve) {
|
|
474
|
-
const oldValue = OnyxCache_1.default.
|
|
509
|
+
const oldValue = OnyxCache_1.default.get(key);
|
|
475
510
|
const newValue = (_a = defaultKeyStates[key]) !== null && _a !== void 0 ? _a : null;
|
|
476
511
|
if (newValue !== oldValue) {
|
|
477
512
|
OnyxCache_1.default.set(key, newValue);
|
|
@@ -496,7 +531,7 @@ function clear(keysToPreserve = []) {
|
|
|
496
531
|
const updatePromises = [];
|
|
497
532
|
// Notify the subscribers for each key/value group so they can receive the new values
|
|
498
533
|
Object.entries(keyValuesToResetIndividually).forEach(([key, value]) => {
|
|
499
|
-
updatePromises.push(OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, OnyxCache_1.default.
|
|
534
|
+
updatePromises.push(OnyxUtils_1.default.scheduleSubscriberUpdate(key, value, OnyxCache_1.default.get(key, false)));
|
|
500
535
|
});
|
|
501
536
|
Object.entries(keyValuesToResetAsCollection).forEach(([key, value]) => {
|
|
502
537
|
updatePromises.push(OnyxUtils_1.default.scheduleNotifyCollectionSubscribers(key, value));
|
package/dist/OnyxCache.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ import type { OnyxKey, OnyxValue } from './types';
|
|
|
5
5
|
*/
|
|
6
6
|
declare class OnyxCache {
|
|
7
7
|
/** Cache of all the storage keys available in persistent storage */
|
|
8
|
-
storageKeys
|
|
8
|
+
private storageKeys;
|
|
9
|
+
/** A list of keys where a nullish value has been fetched from storage before, but the key still exists in cache */
|
|
10
|
+
private nullishStorageKeys;
|
|
9
11
|
/** Unique list of keys maintained in access order (most recent at the end) */
|
|
10
12
|
private recentKeys;
|
|
11
13
|
/** A map of cached values */
|
|
@@ -21,16 +23,32 @@ declare class OnyxCache {
|
|
|
21
23
|
/** Get all the storage keys */
|
|
22
24
|
getAllKeys(): Set<OnyxKey>;
|
|
23
25
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* Allows to set all the keys at once.
|
|
27
|
+
* This is useful when we are getting
|
|
28
|
+
* all the keys from the storage provider
|
|
29
|
+
* and we want to keep the cache in sync.
|
|
30
|
+
*
|
|
31
|
+
* Previously, we had to call `addKey` in a loop
|
|
32
|
+
* to achieve the same result.
|
|
33
|
+
*
|
|
34
|
+
* @param keys - an array of keys
|
|
26
35
|
*/
|
|
27
|
-
|
|
28
|
-
/** Check whether cache has data for the given key */
|
|
29
|
-
hasCacheForKey(key: OnyxKey): boolean;
|
|
36
|
+
setAllKeys(keys: OnyxKey[]): void;
|
|
30
37
|
/** Saves a key in the storage keys list
|
|
31
38
|
* Serves to keep the result of `getAllKeys` up to date
|
|
32
39
|
*/
|
|
33
40
|
addKey(key: OnyxKey): void;
|
|
41
|
+
/** Used to set keys that are null/undefined in storage without adding null to the storage map */
|
|
42
|
+
addNullishStorageKey(key: OnyxKey): void;
|
|
43
|
+
/** Used to clear keys that are null/undefined in cache */
|
|
44
|
+
clearNullishStorageKeys(): void;
|
|
45
|
+
/** Check whether cache has data for the given key */
|
|
46
|
+
hasCacheForKey(key: OnyxKey): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Get a cached value from storage
|
|
49
|
+
* @param [shouldReindexCache] – This is an LRU cache, and by default accessing a value will make it become last in line to be evicted. This flag can be used to skip that and just access the value directly without side-effects.
|
|
50
|
+
*/
|
|
51
|
+
get(key: OnyxKey, shouldReindexCache?: boolean): OnyxValue<OnyxKey>;
|
|
34
52
|
/**
|
|
35
53
|
* Set's a key value in cache
|
|
36
54
|
* Adds the key to the storage keys list as well
|
|
@@ -43,18 +61,6 @@ declare class OnyxCache {
|
|
|
43
61
|
* @param data - a map of (cache) key - values
|
|
44
62
|
*/
|
|
45
63
|
merge(data: Record<OnyxKey, OnyxValue<OnyxKey>>): void;
|
|
46
|
-
/**
|
|
47
|
-
* Allows to set all the keys at once.
|
|
48
|
-
* This is useful when we are getting
|
|
49
|
-
* all the keys from the storage provider
|
|
50
|
-
* and we want to keep the cache in sync.
|
|
51
|
-
*
|
|
52
|
-
* Previously, we had to call `addKey` in a loop
|
|
53
|
-
* to achieve the same result.
|
|
54
|
-
*
|
|
55
|
-
* @param keys - an array of keys
|
|
56
|
-
*/
|
|
57
|
-
setAllKeys(keys: OnyxKey[]): void;
|
|
58
64
|
/**
|
|
59
65
|
* Check whether the given task is already running
|
|
60
66
|
* @param taskName - unique name given for the task
|
package/dist/OnyxCache.js
CHANGED
|
@@ -15,29 +15,30 @@ class OnyxCache {
|
|
|
15
15
|
/** Maximum size of the keys store din cache */
|
|
16
16
|
this.maxRecentKeysSize = 0;
|
|
17
17
|
this.storageKeys = new Set();
|
|
18
|
+
this.nullishStorageKeys = new Set();
|
|
18
19
|
this.recentKeys = new Set();
|
|
19
20
|
this.storageMap = {};
|
|
20
21
|
this.pendingPromises = new Map();
|
|
21
22
|
// bind all public methods to prevent problems with `this`
|
|
22
|
-
(0, bindAll_1.default)(this, 'getAllKeys', '
|
|
23
|
+
(0, bindAll_1.default)(this, 'getAllKeys', 'get', 'hasCacheForKey', 'addKey', 'addNullishStorageKey', 'clearNullishStorageKeys', 'set', 'drop', 'merge', 'hasPendingTask', 'getTaskPromise', 'captureTask', 'removeLeastRecentlyUsedKeys', 'setRecentKeysLimit', 'setAllKeys');
|
|
23
24
|
}
|
|
24
25
|
/** Get all the storage keys */
|
|
25
26
|
getAllKeys() {
|
|
26
27
|
return this.storageKeys;
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* Allows to set all the keys at once.
|
|
31
|
+
* This is useful when we are getting
|
|
32
|
+
* all the keys from the storage provider
|
|
33
|
+
* and we want to keep the cache in sync.
|
|
34
|
+
*
|
|
35
|
+
* Previously, we had to call `addKey` in a loop
|
|
36
|
+
* to achieve the same result.
|
|
37
|
+
*
|
|
38
|
+
* @param keys - an array of keys
|
|
31
39
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.addToAccessedKeys(key);
|
|
35
|
-
}
|
|
36
|
-
return this.storageMap[key];
|
|
37
|
-
}
|
|
38
|
-
/** Check whether cache has data for the given key */
|
|
39
|
-
hasCacheForKey(key) {
|
|
40
|
-
return this.storageMap[key] !== undefined;
|
|
40
|
+
setAllKeys(keys) {
|
|
41
|
+
this.storageKeys = new Set(keys);
|
|
41
42
|
}
|
|
42
43
|
/** Saves a key in the storage keys list
|
|
43
44
|
* Serves to keep the result of `getAllKeys` up to date
|
|
@@ -45,6 +46,28 @@ class OnyxCache {
|
|
|
45
46
|
addKey(key) {
|
|
46
47
|
this.storageKeys.add(key);
|
|
47
48
|
}
|
|
49
|
+
/** Used to set keys that are null/undefined in storage without adding null to the storage map */
|
|
50
|
+
addNullishStorageKey(key) {
|
|
51
|
+
this.nullishStorageKeys.add(key);
|
|
52
|
+
}
|
|
53
|
+
/** Used to clear keys that are null/undefined in cache */
|
|
54
|
+
clearNullishStorageKeys() {
|
|
55
|
+
this.nullishStorageKeys = new Set();
|
|
56
|
+
}
|
|
57
|
+
/** Check whether cache has data for the given key */
|
|
58
|
+
hasCacheForKey(key) {
|
|
59
|
+
return this.storageMap[key] !== undefined || this.nullishStorageKeys.has(key);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get a cached value from storage
|
|
63
|
+
* @param [shouldReindexCache] – This is an LRU cache, and by default accessing a value will make it become last in line to be evicted. This flag can be used to skip that and just access the value directly without side-effects.
|
|
64
|
+
*/
|
|
65
|
+
get(key, shouldReindexCache = true) {
|
|
66
|
+
if (shouldReindexCache) {
|
|
67
|
+
this.addToAccessedKeys(key);
|
|
68
|
+
}
|
|
69
|
+
return this.storageMap[key];
|
|
70
|
+
}
|
|
48
71
|
/**
|
|
49
72
|
* Set's a key value in cache
|
|
50
73
|
* Adds the key to the storage keys list as well
|
|
@@ -52,6 +75,13 @@ class OnyxCache {
|
|
|
52
75
|
set(key, value) {
|
|
53
76
|
this.addKey(key);
|
|
54
77
|
this.addToAccessedKeys(key);
|
|
78
|
+
// When a key is explicitly set in cache, we can remove it from the list of nullish keys,
|
|
79
|
+
// since it will either be set to a non nullish value or removed from the cache completely.
|
|
80
|
+
this.nullishStorageKeys.delete(key);
|
|
81
|
+
if (value === null || value === undefined) {
|
|
82
|
+
delete this.storageMap[key];
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
55
85
|
this.storageMap[key] = value;
|
|
56
86
|
return value;
|
|
57
87
|
}
|
|
@@ -69,25 +99,17 @@ class OnyxCache {
|
|
|
69
99
|
if (typeof data !== 'object' || Array.isArray(data)) {
|
|
70
100
|
throw new Error('data passed to cache.merge() must be an Object of onyx key/value pairs');
|
|
71
101
|
}
|
|
72
|
-
this.storageMap = Object.assign({}, utils_1.default.fastMerge(this.storageMap, data
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
*
|
|
84
|
-
* Previously, we had to call `addKey` in a loop
|
|
85
|
-
* to achieve the same result.
|
|
86
|
-
*
|
|
87
|
-
* @param keys - an array of keys
|
|
88
|
-
*/
|
|
89
|
-
setAllKeys(keys) {
|
|
90
|
-
this.storageKeys = new Set(keys);
|
|
102
|
+
this.storageMap = Object.assign({}, utils_1.default.fastMerge(this.storageMap, data));
|
|
103
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
104
|
+
this.addKey(key);
|
|
105
|
+
this.addToAccessedKeys(key);
|
|
106
|
+
if (value === null || value === undefined) {
|
|
107
|
+
this.addNullishStorageKey(key);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.nullishStorageKeys.delete(key);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
91
113
|
}
|
|
92
114
|
/**
|
|
93
115
|
* Check whether the given task is already running
|
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,
|
|
3
|
+
import type { CollectionKey, CollectionKeyBase, DeepRecord, KeyValueMapping, Mapping, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, WithOnyxConnectOptions } from './types';
|
|
4
4
|
declare const METHOD: {
|
|
5
5
|
readonly SET: "set";
|
|
6
6
|
readonly MERGE: "merge";
|
|
@@ -32,7 +32,7 @@ declare function getDefaultKeyStates(): Record<OnyxKey, OnyxValue<OnyxKey>>;
|
|
|
32
32
|
* @param initialKeyStates - initial data to set when `init()` and `clear()` are called
|
|
33
33
|
* @param safeEvictionKeys - This is an array of keys (individual or collection patterns) that when provided to Onyx are flagged as "safe" for removal.
|
|
34
34
|
*/
|
|
35
|
-
declare function initStoreValues(keys: DeepRecord<string, OnyxKey>, initialKeyStates: Partial<
|
|
35
|
+
declare function initStoreValues(keys: DeepRecord<string, OnyxKey>, initialKeyStates: Partial<KeyValueMapping>, safeEvictionKeys: OnyxKey[]): void;
|
|
36
36
|
/**
|
|
37
37
|
* Sends an action to DevTools extension
|
|
38
38
|
*
|
|
@@ -107,7 +107,7 @@ 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]>,
|
|
110
|
+
declare function keysChanged<TKey extends CollectionKeyBase>(collectionKey: TKey, partialCollection: OnyxCollection<KeyValueMapping[TKey]>, partialPreviousCollection: 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
|
*
|
|
@@ -120,7 +120,7 @@ declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TK
|
|
|
120
120
|
* - sets state on the withOnyxInstances
|
|
121
121
|
* - triggers the callback function
|
|
122
122
|
*/
|
|
123
|
-
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: Mapping<TKey>,
|
|
123
|
+
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: Mapping<TKey>, value: OnyxValue<TKey> | null, matchedKey: TKey | undefined, isBatched: boolean): void;
|
|
124
124
|
/**
|
|
125
125
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
126
126
|
* run out of storage the least recently accessed key can be removed.
|
|
@@ -157,10 +157,10 @@ declare function evictStorageAndRetry<TMethod extends typeof Onyx.set | typeof O
|
|
|
157
157
|
/**
|
|
158
158
|
* Notifies subscribers and writes current value to cache
|
|
159
159
|
*/
|
|
160
|
-
declare function broadcastUpdate<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TKey>, hasChanged?: boolean
|
|
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 = {
|
|
163
|
-
value:
|
|
162
|
+
type RemoveNullValuesOutput<Value extends OnyxValue<OnyxKey> | null> = {
|
|
163
|
+
value: Value | null;
|
|
164
164
|
wasRemoved: boolean;
|
|
165
165
|
};
|
|
166
166
|
/**
|
|
@@ -170,7 +170,7 @@ type RemoveNullValuesOutput = {
|
|
|
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(key: OnyxKey, value:
|
|
173
|
+
declare function removeNullValues<Value extends OnyxValue<OnyxKey>>(key: OnyxKey, value: Value | null, 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}
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -163,7 +163,7 @@ function reduceCollectionWithSelector(collection, selector, withOnyxInstanceStat
|
|
|
163
163
|
function get(key) {
|
|
164
164
|
// When we already have the value in cache - resolve right away
|
|
165
165
|
if (OnyxCache_1.default.hasCacheForKey(key)) {
|
|
166
|
-
return Promise.resolve(OnyxCache_1.default.
|
|
166
|
+
return Promise.resolve(OnyxCache_1.default.get(key));
|
|
167
167
|
}
|
|
168
168
|
const taskName = `get:${key}`;
|
|
169
169
|
// When a value retrieving task for this key is still running hook to it
|
|
@@ -173,6 +173,10 @@ function get(key) {
|
|
|
173
173
|
// Otherwise retrieve the value from storage and capture a promise to aid concurrent usages
|
|
174
174
|
const promise = storage_1.default.getItem(key)
|
|
175
175
|
.then((val) => {
|
|
176
|
+
if (val === undefined) {
|
|
177
|
+
OnyxCache_1.default.addNullishStorageKey(key);
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
176
180
|
OnyxCache_1.default.set(key, val);
|
|
177
181
|
return val;
|
|
178
182
|
})
|
|
@@ -182,9 +186,9 @@ function get(key) {
|
|
|
182
186
|
/** Returns current key names stored in persisted storage */
|
|
183
187
|
function getAllKeys() {
|
|
184
188
|
// When we've already read stored keys, resolve right away
|
|
185
|
-
const
|
|
186
|
-
if (
|
|
187
|
-
return Promise.resolve(
|
|
189
|
+
const cachedKeys = OnyxCache_1.default.getAllKeys();
|
|
190
|
+
if (cachedKeys.size > 0) {
|
|
191
|
+
return Promise.resolve(cachedKeys);
|
|
188
192
|
}
|
|
189
193
|
const taskName = 'getAllKeys';
|
|
190
194
|
// When a value retrieving task for all keys is still running hook to it
|
|
@@ -237,7 +241,7 @@ function isSafeEvictionKey(testKey) {
|
|
|
237
241
|
* If the requested key is a collection, it will return an object with all the collection members.
|
|
238
242
|
*/
|
|
239
243
|
function tryGetCachedValue(key, mapping) {
|
|
240
|
-
let val = OnyxCache_1.default.
|
|
244
|
+
let val = OnyxCache_1.default.get(key);
|
|
241
245
|
if (isCollectionKey(key)) {
|
|
242
246
|
const allCacheKeys = OnyxCache_1.default.getAllKeys();
|
|
243
247
|
// It is possible we haven't loaded all keys yet so we do not know if the
|
|
@@ -247,7 +251,7 @@ function tryGetCachedValue(key, mapping) {
|
|
|
247
251
|
}
|
|
248
252
|
const matchingKeys = Array.from(allCacheKeys).filter((k) => k.startsWith(key));
|
|
249
253
|
const values = matchingKeys.reduce((finalObject, matchedKey) => {
|
|
250
|
-
const cachedValue = OnyxCache_1.default.
|
|
254
|
+
const cachedValue = OnyxCache_1.default.get(matchedKey);
|
|
251
255
|
if (cachedValue) {
|
|
252
256
|
// This is permissible because we're in the process of constructing the final object in a reduce function.
|
|
253
257
|
// eslint-disable-next-line no-param-reassign
|
|
@@ -334,23 +338,22 @@ function getCachedCollection(collectionKey, collectionMemberKeys) {
|
|
|
334
338
|
if (!collectionMemberKeys && !isCollectionMemberKey(collectionKey, key)) {
|
|
335
339
|
return;
|
|
336
340
|
}
|
|
337
|
-
collection[key] = OnyxCache_1.default.
|
|
341
|
+
collection[key] = OnyxCache_1.default.get(key);
|
|
338
342
|
});
|
|
339
343
|
return collection;
|
|
340
344
|
}
|
|
341
345
|
/**
|
|
342
346
|
* When a collection of keys change, search for any callbacks matching the collection key and trigger those callbacks
|
|
343
347
|
*/
|
|
344
|
-
function keysChanged(collectionKey, partialCollection,
|
|
345
|
-
const previousCollectionWithoutNestedNulls = previousPartialCollection === undefined ? {} : utils_1.default.removeNestedNullValues(previousPartialCollection);
|
|
348
|
+
function keysChanged(collectionKey, partialCollection, partialPreviousCollection, notifyRegularSubscibers = true, notifyWithOnyxSubscibers = true) {
|
|
346
349
|
// We prepare the "cached collection" which is the entire collection + the new partial data that
|
|
347
350
|
// was merged in via mergeCollection().
|
|
348
351
|
const cachedCollection = getCachedCollection(collectionKey);
|
|
349
|
-
const cachedCollectionWithoutNestedNulls = utils_1.default.removeNestedNullValues(cachedCollection);
|
|
350
352
|
// If the previous collection equals the new collection then we do not need to notify any subscribers.
|
|
351
|
-
if (
|
|
353
|
+
if (partialPreviousCollection !== undefined && (0, fast_equals_1.deepEqual)(cachedCollection, partialPreviousCollection)) {
|
|
352
354
|
return;
|
|
353
355
|
}
|
|
356
|
+
const previousCollection = partialPreviousCollection !== null && partialPreviousCollection !== void 0 ? partialPreviousCollection : {};
|
|
354
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
|
|
355
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
|
|
356
359
|
// 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().
|
|
@@ -381,7 +384,7 @@ function keysChanged(collectionKey, partialCollection, previousPartialCollection
|
|
|
381
384
|
// send the whole cached collection.
|
|
382
385
|
if (isSubscribedToCollectionKey) {
|
|
383
386
|
if (subscriber.waitForCollectionCallback) {
|
|
384
|
-
subscriber.callback(
|
|
387
|
+
subscriber.callback(cachedCollection);
|
|
385
388
|
continue;
|
|
386
389
|
}
|
|
387
390
|
// If they are not using waitForCollectionCallback then we notify the subscriber with
|
|
@@ -389,21 +392,21 @@ function keysChanged(collectionKey, partialCollection, previousPartialCollection
|
|
|
389
392
|
const dataKeys = Object.keys(partialCollection !== null && partialCollection !== void 0 ? partialCollection : {});
|
|
390
393
|
for (let j = 0; j < dataKeys.length; j++) {
|
|
391
394
|
const dataKey = dataKeys[j];
|
|
392
|
-
if ((0, fast_equals_1.deepEqual)(
|
|
395
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollection[dataKey], previousCollection[dataKey])) {
|
|
393
396
|
continue;
|
|
394
397
|
}
|
|
395
|
-
subscriber.callback(
|
|
398
|
+
subscriber.callback(cachedCollection[dataKey], dataKey);
|
|
396
399
|
}
|
|
397
400
|
continue;
|
|
398
401
|
}
|
|
399
402
|
// And if the subscriber is specifically only tracking a particular collection member key then we will
|
|
400
403
|
// notify them with the cached data for that key only.
|
|
401
404
|
if (isSubscribedToCollectionMemberKey) {
|
|
402
|
-
if ((0, fast_equals_1.deepEqual)(
|
|
405
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollection[subscriber.key], previousCollection[subscriber.key])) {
|
|
403
406
|
continue;
|
|
404
407
|
}
|
|
405
408
|
const subscriberCallback = subscriber.callback;
|
|
406
|
-
subscriberCallback(
|
|
409
|
+
subscriberCallback(cachedCollection[subscriber.key], subscriber.key);
|
|
407
410
|
continue;
|
|
408
411
|
}
|
|
409
412
|
continue;
|
|
@@ -449,7 +452,7 @@ function keysChanged(collectionKey, partialCollection, previousPartialCollection
|
|
|
449
452
|
}
|
|
450
453
|
// If a React component is only interested in a single key then we can set the cached value directly to the state name.
|
|
451
454
|
if (isSubscribedToCollectionMemberKey) {
|
|
452
|
-
if ((0, fast_equals_1.deepEqual)(
|
|
455
|
+
if ((0, fast_equals_1.deepEqual)(cachedCollection[subscriber.key], previousCollection[subscriber.key])) {
|
|
453
456
|
continue;
|
|
454
457
|
}
|
|
455
458
|
// However, we only want to update this subscriber if the partial data contains a change.
|
|
@@ -525,14 +528,12 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
525
528
|
}
|
|
526
529
|
if (isCollectionKey(subscriber.key) && subscriber.waitForCollectionCallback) {
|
|
527
530
|
const cachedCollection = getCachedCollection(subscriber.key);
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
subscriber.callback(cachedCollectionWithoutNestedNulls);
|
|
531
|
+
cachedCollection[key] = value;
|
|
532
|
+
subscriber.callback(cachedCollection);
|
|
531
533
|
continue;
|
|
532
534
|
}
|
|
533
|
-
const valueWithoutNestedNulls = utils_1.default.removeNestedNullValues(value);
|
|
534
535
|
const subscriberCallback = subscriber.callback;
|
|
535
|
-
subscriberCallback(
|
|
536
|
+
subscriberCallback(value, key);
|
|
536
537
|
continue;
|
|
537
538
|
}
|
|
538
539
|
// Subscriber connected via withOnyx() HOC
|
|
@@ -612,7 +613,7 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
612
613
|
* - sets state on the withOnyxInstances
|
|
613
614
|
* - triggers the callback function
|
|
614
615
|
*/
|
|
615
|
-
function sendDataToConnection(mapping,
|
|
616
|
+
function sendDataToConnection(mapping, value, matchedKey, isBatched) {
|
|
616
617
|
var _a, _b;
|
|
617
618
|
// If the mapping no longer exists then we should not send any data.
|
|
618
619
|
// This means our subscriber disconnected or withOnyx wrapped component unmounted.
|
|
@@ -620,15 +621,15 @@ function sendDataToConnection(mapping, val, matchedKey, isBatched) {
|
|
|
620
621
|
return;
|
|
621
622
|
}
|
|
622
623
|
if ('withOnyxInstance' in mapping && mapping.withOnyxInstance) {
|
|
623
|
-
let newData =
|
|
624
|
+
let newData = value;
|
|
624
625
|
// If the mapping has a selector, then the component's state must only be updated with the data
|
|
625
626
|
// returned by the selector.
|
|
626
627
|
if (mapping.selector) {
|
|
627
628
|
if (isCollectionKey(mapping.key)) {
|
|
628
|
-
newData = reduceCollectionWithSelector(
|
|
629
|
+
newData = reduceCollectionWithSelector(value, mapping.selector, mapping.withOnyxInstance.state);
|
|
629
630
|
}
|
|
630
631
|
else {
|
|
631
|
-
newData = mapping.selector(
|
|
632
|
+
newData = mapping.selector(value, mapping.withOnyxInstance.state);
|
|
632
633
|
}
|
|
633
634
|
}
|
|
634
635
|
PerformanceUtils.logSetStateCall(mapping, null, newData, 'sendDataToConnection');
|
|
@@ -640,8 +641,13 @@ function sendDataToConnection(mapping, val, matchedKey, isBatched) {
|
|
|
640
641
|
}
|
|
641
642
|
return;
|
|
642
643
|
}
|
|
643
|
-
|
|
644
|
-
|
|
644
|
+
// When there are no matching keys in "Onyx.connect", we pass null to "sendDataToConnection" explicitly,
|
|
645
|
+
// to allow the withOnyx instance to set the value in the state initially and therefore stop the loading state once all
|
|
646
|
+
// required keys have been set.
|
|
647
|
+
// If we would pass undefined to setWithOnyxInstance instead, withOnyx would not set the value in the state.
|
|
648
|
+
// withOnyx will internally replace null values with undefined and never pass null values to wrapped components.
|
|
649
|
+
// For regular callbacks, we never want to pass null values, but always just undefined if a value is not set in cache or storage.
|
|
650
|
+
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, value === null ? undefined : value, matchedKey);
|
|
645
651
|
}
|
|
646
652
|
/**
|
|
647
653
|
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
@@ -682,7 +688,7 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
682
688
|
* These missingKeys will be later to use to multiGet the data from the storage.
|
|
683
689
|
*/
|
|
684
690
|
matchingKeys.forEach((key) => {
|
|
685
|
-
const cacheValue = OnyxCache_1.default.
|
|
691
|
+
const cacheValue = OnyxCache_1.default.get(key);
|
|
686
692
|
if (cacheValue) {
|
|
687
693
|
data[key] = cacheValue;
|
|
688
694
|
return;
|
|
@@ -755,7 +761,7 @@ function scheduleNotifyCollectionSubscribers(key, value, previousValue) {
|
|
|
755
761
|
* Remove a key from Onyx and update the subscribers
|
|
756
762
|
*/
|
|
757
763
|
function remove(key) {
|
|
758
|
-
const prevValue = OnyxCache_1.default.
|
|
764
|
+
const prevValue = OnyxCache_1.default.get(key, false);
|
|
759
765
|
OnyxCache_1.default.drop(key);
|
|
760
766
|
scheduleSubscriberUpdate(key, null, prevValue);
|
|
761
767
|
return storage_1.default.removeItem(key).then(() => undefined);
|
|
@@ -798,11 +804,11 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
798
804
|
/**
|
|
799
805
|
* Notifies subscribers and writes current value to cache
|
|
800
806
|
*/
|
|
801
|
-
function broadcastUpdate(key, value, hasChanged
|
|
802
|
-
const prevValue = OnyxCache_1.default.
|
|
807
|
+
function broadcastUpdate(key, value, hasChanged) {
|
|
808
|
+
const prevValue = OnyxCache_1.default.get(key, false);
|
|
803
809
|
// Update subscribers if the cached value has changed, or when the subscriber specifically requires
|
|
804
810
|
// all updates regardless of value changes (indicated by initWithStoredValues set to false).
|
|
805
|
-
if (hasChanged
|
|
811
|
+
if (hasChanged) {
|
|
806
812
|
OnyxCache_1.default.set(key, value);
|
|
807
813
|
}
|
|
808
814
|
else {
|
|
@@ -823,7 +829,7 @@ function hasPendingMergeForKey(key) {
|
|
|
823
829
|
function removeNullValues(key, value, shouldRemoveNestedNulls = true) {
|
|
824
830
|
if (value === null) {
|
|
825
831
|
remove(key);
|
|
826
|
-
return { value, wasRemoved: true };
|
|
832
|
+
return { value: null, wasRemoved: true };
|
|
827
833
|
}
|
|
828
834
|
// We can remove all null values in an object by merging it with itself
|
|
829
835
|
// utils.fastMerge recursively goes through the object and removes all null values
|
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, OnyxKey, OnyxValue, Selector } from './types';
|
|
3
|
+
import type { CustomTypeOptions, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxInput, OnyxKey, OnyxValue, Selector, 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, OnyxKey, OnyxUpdate, OnyxValue, ResultMetadata, Selector, UseOnyxResult, WithOnyxState, };
|
|
10
|
+
export type { ConnectOptions, CustomTypeOptions, FetchStatus, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxInput, OnyxKey, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, ResultMetadata, Selector, UseOnyxResult, WithOnyxState, };
|
|
@@ -22,14 +22,26 @@ const provider = {
|
|
|
22
22
|
throw Error('IDBKeyVal store could not be created');
|
|
23
23
|
idbKeyValStore = newIdbKeyValStore;
|
|
24
24
|
},
|
|
25
|
-
setItem: (key, value) =>
|
|
25
|
+
setItem: (key, value) => {
|
|
26
|
+
if (value === null) {
|
|
27
|
+
provider.removeItem(key);
|
|
28
|
+
}
|
|
29
|
+
return (0, idb_keyval_1.set)(key, value, idbKeyValStore);
|
|
30
|
+
},
|
|
26
31
|
multiGet: (keysParam) => (0, idb_keyval_1.getMany)(keysParam, idbKeyValStore).then((values) => values.map((value, index) => [keysParam[index], value])),
|
|
27
32
|
multiMerge: (pairs) => idbKeyValStore('readwrite', (store) => {
|
|
28
33
|
// Note: we are using the manual store transaction here, to fit the read and update
|
|
29
34
|
// of the items in one transaction to achieve best performance.
|
|
30
35
|
const getValues = Promise.all(pairs.map(([key]) => (0, idb_keyval_1.promisifyRequest)(store.get(key))));
|
|
31
36
|
return getValues.then((values) => {
|
|
32
|
-
const
|
|
37
|
+
const pairsWithoutNull = pairs.filter(([key, value]) => {
|
|
38
|
+
if (value === null) {
|
|
39
|
+
provider.removeItem(key);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
});
|
|
44
|
+
const upsertMany = pairsWithoutNull.map(([key, value], index) => {
|
|
33
45
|
const prev = values[index];
|
|
34
46
|
const newValue = utils_1.default.fastMerge(prev, value);
|
|
35
47
|
return (0, idb_keyval_1.promisifyRequest)(store.put(newValue, key));
|
|
@@ -41,7 +53,16 @@ const provider = {
|
|
|
41
53
|
// Since Onyx also merged the existing value with the changes, we can just set the value directly
|
|
42
54
|
return provider.setItem(key, preMergedValue);
|
|
43
55
|
},
|
|
44
|
-
multiSet: (pairs) =>
|
|
56
|
+
multiSet: (pairs) => {
|
|
57
|
+
const pairsWithoutNull = pairs.filter(([key, value]) => {
|
|
58
|
+
if (value === null) {
|
|
59
|
+
provider.removeItem(key);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
});
|
|
64
|
+
return (0, idb_keyval_1.setMany)(pairsWithoutNull, idbKeyValStore);
|
|
65
|
+
},
|
|
45
66
|
clear: () => (0, idb_keyval_1.clear)(idbKeyValStore),
|
|
46
67
|
getAllKeys: () => (0, idb_keyval_1.keys)(idbKeyValStore),
|
|
47
68
|
getItem: (key) => (0, idb_keyval_1.get)(key, idbKeyValStore)
|
package/dist/types.d.ts
CHANGED
|
@@ -121,7 +121,7 @@ type KeyValueMapping = {
|
|
|
121
121
|
* It's very similar to `KeyValueMapping` but this type accepts using `null` as well.
|
|
122
122
|
*/
|
|
123
123
|
type NullableKeyValueMapping = {
|
|
124
|
-
[TKey in OnyxKey]: OnyxValue<TKey
|
|
124
|
+
[TKey in OnyxKey]: NonUndefined<OnyxValue<TKey>> | null;
|
|
125
125
|
};
|
|
126
126
|
/**
|
|
127
127
|
* Represents a selector function type which operates based on the provided `TKey` and `ReturnType`.
|
|
@@ -161,7 +161,13 @@ type Selector<TKey extends OnyxKey, TOnyxProps, TReturnType> = (value: OnyxEntry
|
|
|
161
161
|
* })(Component);
|
|
162
162
|
* ```
|
|
163
163
|
*/
|
|
164
|
-
type OnyxEntry<TOnyxValue> = TOnyxValue |
|
|
164
|
+
type OnyxEntry<TOnyxValue> = TOnyxValue | undefined;
|
|
165
|
+
/**
|
|
166
|
+
* Represents an input value that can be passed to Onyx methods, that can be either `TOnyxValue` or `null`.
|
|
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;
|
|
165
171
|
/**
|
|
166
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.
|
|
167
173
|
*
|
|
@@ -190,7 +196,7 @@ type OnyxEntry<TOnyxValue> = TOnyxValue | null | undefined;
|
|
|
190
196
|
* })(Component);
|
|
191
197
|
* ```
|
|
192
198
|
*/
|
|
193
|
-
type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue |
|
|
199
|
+
type OnyxCollection<TOnyxValue> = OnyxEntry<Record<string, TOnyxValue | undefined>>;
|
|
194
200
|
/** Utility type to extract `TOnyxValue` from `OnyxCollection<TOnyxValue>` */
|
|
195
201
|
type ExtractOnyxCollectionValue<TOnyxCollection> = TOnyxCollection extends NonNullable<OnyxCollection<infer U>> ? U : never;
|
|
196
202
|
type NonTransformableTypes = BuiltIns | ((...args: any[]) => unknown) | Map<unknown, unknown> | Set<unknown> | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | unknown[] | readonly unknown[];
|
|
@@ -229,7 +235,7 @@ type NullishObjectDeep<ObjectType extends object> = {
|
|
|
229
235
|
* Also, the `TMap` type is inferred automatically in `mergeCollection()` method and represents
|
|
230
236
|
* the object of collection keys/values specified in the second parameter of the method.
|
|
231
237
|
*/
|
|
232
|
-
type Collection<TKey extends CollectionKeyBase,
|
|
238
|
+
type Collection<TKey extends CollectionKeyBase, TValue, TMap = never> = {
|
|
233
239
|
[MapK in keyof TMap]: MapK extends `${TKey}${string}` ? MapK extends `${TKey}` ? never : TValue : never;
|
|
234
240
|
};
|
|
235
241
|
/** Represents the base options used in `Onyx.connect()` method. */
|
|
@@ -276,6 +282,22 @@ type ConnectOptions<TKey extends OnyxKey> = (CollectionConnectOptions<TKey> | De
|
|
|
276
282
|
type Mapping<TKey extends OnyxKey> = ConnectOptions<TKey> & {
|
|
277
283
|
connectionID: number;
|
|
278
284
|
};
|
|
285
|
+
/**
|
|
286
|
+
* This represents the value that can be passed to `Onyx.set` and to `Onyx.update` with the method "SET"
|
|
287
|
+
*/
|
|
288
|
+
type OnyxSetInput<TKey extends OnyxKey> = OnyxInput<KeyValueMapping[TKey]>;
|
|
289
|
+
/**
|
|
290
|
+
* This represents the value that can be passed to `Onyx.multiSet` and to `Onyx.update` with the method "MULTI_SET"
|
|
291
|
+
*/
|
|
292
|
+
type OnyxMultiSetInput = Partial<NullableKeyValueMapping>;
|
|
293
|
+
/**
|
|
294
|
+
* This represents the value that can be passed to `Onyx.merge` and to `Onyx.update` with the method "MERGE"
|
|
295
|
+
*/
|
|
296
|
+
type OnyxMergeInput<TKey extends OnyxKey> = OnyxInput<NullishDeep<KeyValueMapping[TKey]>>;
|
|
297
|
+
/**
|
|
298
|
+
* This represents the value that can be passed to `Onyx.merge` and to `Onyx.update` with the method "MERGE"
|
|
299
|
+
*/
|
|
300
|
+
type OnyxMergeCollectionInput<TKey extends OnyxKey, TMap = object> = Collection<TKey, NullishDeep<KeyValueMapping[TKey]>, TMap>;
|
|
279
301
|
/**
|
|
280
302
|
* Represents different kinds of updates that can be passed to `Onyx.update()` method. It is a discriminated union of
|
|
281
303
|
* different update methods (`SET`, `MERGE`, `MERGE_COLLECTION`), each with their own key and value structure.
|
|
@@ -284,15 +306,15 @@ type OnyxUpdate = {
|
|
|
284
306
|
[TKey in OnyxKey]: {
|
|
285
307
|
onyxMethod: typeof OnyxUtils.METHOD.SET;
|
|
286
308
|
key: TKey;
|
|
287
|
-
value:
|
|
309
|
+
value: OnyxSetInput<TKey>;
|
|
288
310
|
} | {
|
|
289
|
-
onyxMethod: typeof OnyxUtils.METHOD.
|
|
311
|
+
onyxMethod: typeof OnyxUtils.METHOD.MULTI_SET;
|
|
290
312
|
key: TKey;
|
|
291
|
-
value:
|
|
313
|
+
value: OnyxMultiSetInput;
|
|
292
314
|
} | {
|
|
293
|
-
onyxMethod: typeof OnyxUtils.METHOD.
|
|
315
|
+
onyxMethod: typeof OnyxUtils.METHOD.MERGE;
|
|
294
316
|
key: TKey;
|
|
295
|
-
value:
|
|
317
|
+
value: OnyxMergeInput<TKey>;
|
|
296
318
|
} | {
|
|
297
319
|
onyxMethod: typeof OnyxUtils.METHOD.CLEAR;
|
|
298
320
|
key: TKey;
|
|
@@ -302,7 +324,7 @@ type OnyxUpdate = {
|
|
|
302
324
|
[TKey in CollectionKeyBase]: {
|
|
303
325
|
onyxMethod: typeof OnyxUtils.METHOD.MERGE_COLLECTION;
|
|
304
326
|
key: TKey;
|
|
305
|
-
value:
|
|
327
|
+
value: OnyxMergeCollectionInput<TKey>;
|
|
306
328
|
};
|
|
307
329
|
}[CollectionKeyBase];
|
|
308
330
|
/**
|
|
@@ -333,4 +355,4 @@ type InitOptions = {
|
|
|
333
355
|
debugSetState?: boolean;
|
|
334
356
|
};
|
|
335
357
|
type GenericFunction = (...args: any[]) => any;
|
|
336
|
-
export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, NullableKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, };
|
|
358
|
+
export type { BaseConnectOptions, Collection, CollectionConnectCallback, CollectionConnectOptions, CollectionKey, CollectionKeyBase, ConnectOptions, CustomTypeOptions, DeepRecord, DefaultConnectCallback, DefaultConnectOptions, ExtractOnyxCollectionValue, GenericFunction, InitOptions, Key, KeyValueMapping, Mapping, NonNull, NonUndefined, NullableKeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxInput, OnyxKey, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, Selector, WithOnyxConnectOptions, };
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OnyxKey } from './types';
|
|
1
|
+
import type { OnyxKey, OnyxValue } 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. */
|
|
@@ -12,7 +12,7 @@ declare function isEmptyObject<T>(obj: T | EmptyValue): obj is EmptyValue;
|
|
|
12
12
|
*/
|
|
13
13
|
declare function fastMerge<TObject extends Record<string, unknown>>(target: TObject | null, source: TObject | null, shouldRemoveNestedNulls?: boolean): TObject | null;
|
|
14
14
|
/** Deep removes the nested null values from the given value. */
|
|
15
|
-
declare function removeNestedNullValues<
|
|
15
|
+
declare function removeNestedNullValues<TValue extends OnyxValue<OnyxKey> | unknown | unknown[]>(value: TValue | null): TValue | null;
|
|
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
|
@@ -90,7 +90,8 @@ function fastMerge(target, source, shouldRemoveNestedNulls = true) {
|
|
|
90
90
|
/** Deep removes the nested null values from the given value. */
|
|
91
91
|
function removeNestedNullValues(value) {
|
|
92
92
|
if (typeof value === 'object' && !Array.isArray(value)) {
|
|
93
|
-
|
|
93
|
+
const objectValue = value;
|
|
94
|
+
return fastMerge(objectValue, objectValue);
|
|
94
95
|
}
|
|
95
96
|
return value;
|
|
96
97
|
}
|
package/dist/withOnyx/index.js
CHANGED
|
@@ -36,6 +36,7 @@ const Onyx_1 = __importDefault(require("../Onyx"));
|
|
|
36
36
|
const OnyxUtils_1 = __importDefault(require("../OnyxUtils"));
|
|
37
37
|
const Str = __importStar(require("../Str"));
|
|
38
38
|
const utils_1 = __importDefault(require("../utils"));
|
|
39
|
+
const OnyxCache_1 = __importDefault(require("../OnyxCache"));
|
|
39
40
|
// This is a list of keys that can exist on a `mapping`, but are not directly related to loading data from Onyx. When the keys of a mapping are looped over to check
|
|
40
41
|
// if a key has changed, it's a good idea to skip looking at these properties since they would have unexpected results.
|
|
41
42
|
const mappingPropertiesToIgnoreChangesTo = ['initialValue', 'allowStaleData'];
|
|
@@ -85,7 +86,8 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
85
86
|
const cachedState = mapOnyxToStateEntries(mapOnyxToState).reduce((resultObj, [propName, mapping]) => {
|
|
86
87
|
const key = Str.result(mapping.key, props);
|
|
87
88
|
let value = OnyxUtils_1.default.tryGetCachedValue(key, mapping);
|
|
88
|
-
|
|
89
|
+
const hasCacheForKey = OnyxCache_1.default.hasCacheForKey(key);
|
|
90
|
+
if (!hasCacheForKey && !value && mapping.initialValue) {
|
|
89
91
|
value = mapping.initialValue;
|
|
90
92
|
}
|
|
91
93
|
/**
|
|
@@ -99,7 +101,10 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
99
101
|
* In reality, Onyx.merge() will only update the subscriber after all merges have been batched and the previous value is retrieved via a get() (returns a promise).
|
|
100
102
|
* So, we won't use the cache optimization here as it will lead us to arbitrarily defer various actions in the application code.
|
|
101
103
|
*/
|
|
102
|
-
|
|
104
|
+
const hasPendingMergeForKey = OnyxUtils_1.default.hasPendingMergeForKey(key);
|
|
105
|
+
const hasValueInCache = hasCacheForKey || value !== undefined;
|
|
106
|
+
const shouldSetState = mapping.initWithStoredValues !== false && ((hasValueInCache && !hasPendingMergeForKey) || !!mapping.allowStaleData);
|
|
107
|
+
if (shouldSetState) {
|
|
103
108
|
// eslint-disable-next-line no-param-reassign
|
|
104
109
|
resultObj[propName] = value;
|
|
105
110
|
}
|
|
@@ -183,7 +188,7 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
183
188
|
* initialValue is there, we just check if the update is different than that and then try to handle it as best as we can.
|
|
184
189
|
*/
|
|
185
190
|
setWithOnyxState(statePropertyName, val) {
|
|
186
|
-
const
|
|
191
|
+
const prevVal = this.state[statePropertyName];
|
|
187
192
|
// If the component is not loading (read "mounting"), then we can just update the state
|
|
188
193
|
// There is a small race condition.
|
|
189
194
|
// When calling setWithOnyxState we delete the tempState object that is used to hold temporary state updates while the HOC is gathering data.
|
|
@@ -193,10 +198,11 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
193
198
|
// This simply bypasses the loading check if the tempState is gone and the update can be safely queued with a normal setStateProxy.
|
|
194
199
|
if (!this.state.loading || !this.tempState) {
|
|
195
200
|
// Performance optimization, do not trigger update with same values
|
|
196
|
-
if (
|
|
201
|
+
if (prevVal === val || (utils_1.default.isEmptyObject(prevVal) && utils_1.default.isEmptyObject(val))) {
|
|
197
202
|
return;
|
|
198
203
|
}
|
|
199
|
-
|
|
204
|
+
const valueWithoutNull = val === null ? undefined : val;
|
|
205
|
+
this.setStateProxy({ [statePropertyName]: valueWithoutNull });
|
|
200
206
|
return;
|
|
201
207
|
}
|
|
202
208
|
this.tempState[statePropertyName] = val;
|
|
@@ -217,16 +223,16 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
217
223
|
const initialValue = mapOnyxToState[key].initialValue;
|
|
218
224
|
// If initialValue is there and the state contains something different it means
|
|
219
225
|
// an update has already been received and we can discard the value we are trying to hydrate
|
|
220
|
-
if (initialValue !== undefined && prevState[key] !== undefined && prevState[key] !== initialValue) {
|
|
226
|
+
if (initialValue !== undefined && prevState[key] !== undefined && prevState[key] !== initialValue && prevState[key] !== null) {
|
|
221
227
|
// eslint-disable-next-line no-param-reassign
|
|
222
228
|
result[key] = prevState[key];
|
|
223
|
-
// if value is already there (without initial value) then we can discard the value we are trying to hydrate
|
|
224
229
|
}
|
|
225
|
-
else if (prevState[key] !== undefined) {
|
|
230
|
+
else if (prevState[key] !== undefined && prevState[key] !== null) {
|
|
231
|
+
// if value is already there (without initial value) then we can discard the value we are trying to hydrate
|
|
226
232
|
// eslint-disable-next-line no-param-reassign
|
|
227
233
|
result[key] = prevState[key];
|
|
228
234
|
}
|
|
229
|
-
else {
|
|
235
|
+
else if (stateUpdate[key] !== null) {
|
|
230
236
|
// eslint-disable-next-line no-param-reassign
|
|
231
237
|
result[key] = stateUpdate[key];
|
|
232
238
|
}
|
|
@@ -300,9 +306,8 @@ function default_1(mapOnyxToState, shouldDelayUpdates = false) {
|
|
|
300
306
|
// Remove any internal state properties used by withOnyx
|
|
301
307
|
// that should not be passed to a wrapped component
|
|
302
308
|
const stateToPass = utils_1.default.omit(this.state, ([stateKey, stateValue]) => stateKey === 'loading' || stateValue === null);
|
|
303
|
-
const stateToPassWithoutNestedNulls = utils_1.default.removeNestedNullValues(stateToPass);
|
|
304
309
|
// Spreading props and state is necessary in an HOC where the data cannot be predicted
|
|
305
|
-
return (react_1.default.createElement(WrappedComponent, Object.assign({ markReadyForHydration: this.flushPendingSetStates }, propsToPass,
|
|
310
|
+
return (react_1.default.createElement(WrappedComponent, Object.assign({ markReadyForHydration: this.flushPendingSetStates }, propsToPass, stateToPass, { ref: this.props.forwardedRef })));
|
|
306
311
|
}
|
|
307
312
|
}
|
|
308
313
|
withOnyx.displayName = `withOnyx(${displayName})`;
|
package/dist/withOnyx/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ForwardedRef } from 'react';
|
|
2
2
|
import type { IsEqual } from 'type-fest';
|
|
3
|
-
import type { CollectionKeyBase, ExtractOnyxCollectionValue, KeyValueMapping,
|
|
3
|
+
import type { CollectionKeyBase, ExtractOnyxCollectionValue, KeyValueMapping, OnyxCollection, OnyxEntry, OnyxKey, OnyxValue, Selector } from '../types';
|
|
4
4
|
/**
|
|
5
5
|
* Represents the base mapping options between an Onyx key and the component's prop.
|
|
6
6
|
*/
|
|
@@ -134,7 +134,7 @@ type WithOnyxState<TOnyxProps> = TOnyxProps & {
|
|
|
134
134
|
/**
|
|
135
135
|
* Represents the `withOnyx` internal component instance.
|
|
136
136
|
*/
|
|
137
|
-
type WithOnyxInstance = React.Component<unknown, WithOnyxState<
|
|
137
|
+
type WithOnyxInstance = React.Component<unknown, WithOnyxState<KeyValueMapping>> & {
|
|
138
138
|
setStateProxy: (modifier: Record<string, OnyxCollection<KeyValueMapping[OnyxKey]>> | ((state: Record<string, OnyxCollection<KeyValueMapping[OnyxKey]>>) => OnyxValue<OnyxKey>)) => void;
|
|
139
139
|
setWithOnyxState: (statePropertyName: OnyxKey, value: OnyxValue<OnyxKey>) => void;
|
|
140
140
|
};
|