react-native-onyx 2.0.64 → 2.0.66
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/API.md +27 -23
- package/dist/Onyx.d.ts +31 -26
- package/dist/Onyx.js +32 -126
- package/dist/OnyxConnectionManager.d.ts +69 -0
- package/dist/OnyxConnectionManager.js +195 -0
- package/dist/OnyxUtils.d.ts +28 -37
- package/dist/OnyxUtils.js +158 -65
- package/dist/Str.d.ts +5 -1
- package/dist/Str.js +13 -1
- package/dist/createDeferredTask.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/types.d.ts +40 -19
- package/dist/useOnyx.d.ts +2 -2
- package/dist/useOnyx.js +24 -20
- package/dist/utils.d.ts +6 -1
- package/dist/utils.js +7 -1
- package/dist/withOnyx/index.js +10 -10
- package/dist/withOnyx/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/OnyxUtils.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
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, OnyxInput, OnyxKey, OnyxMergeCollectionInput, OnyxValue
|
|
3
|
+
import type { CollectionKey, CollectionKeyBase, ConnectOptions, DeepRecord, KeyValueMapping, Mapping, OnyxCollection, OnyxEntry, OnyxInput, OnyxKey, OnyxMergeCollectionInput, OnyxValue } from './types';
|
|
4
|
+
import type { DeferredTask } from './createDeferredTask';
|
|
4
5
|
declare const METHOD: {
|
|
5
6
|
readonly SET: "set";
|
|
6
7
|
readonly MERGE: "merge";
|
|
@@ -18,14 +19,18 @@ declare function getMergeQueue(): Record<OnyxKey, Array<OnyxValue<OnyxKey>>>;
|
|
|
18
19
|
* Getter - returns the merge queue promise.
|
|
19
20
|
*/
|
|
20
21
|
declare function getMergeQueuePromise(): Record<OnyxKey, Promise<void>>;
|
|
21
|
-
/**
|
|
22
|
-
* Getter - returns the callback to state mapping.
|
|
23
|
-
*/
|
|
24
|
-
declare function getCallbackToStateMapping(): Record<string, Mapping<OnyxKey>>;
|
|
25
22
|
/**
|
|
26
23
|
* Getter - returns the default key states.
|
|
27
24
|
*/
|
|
28
25
|
declare function getDefaultKeyStates(): Record<OnyxKey, OnyxValue<OnyxKey>>;
|
|
26
|
+
/**
|
|
27
|
+
* Getter - returns the deffered init task.
|
|
28
|
+
*/
|
|
29
|
+
declare function getDeferredInitTask(): DeferredTask;
|
|
30
|
+
/**
|
|
31
|
+
* Getter - returns the eviction block list.
|
|
32
|
+
*/
|
|
33
|
+
declare function getEvictionBlocklist(): Record<OnyxKey, string[] | undefined>;
|
|
29
34
|
/**
|
|
30
35
|
* Sets the initial values for the Onyx store
|
|
31
36
|
*
|
|
@@ -55,19 +60,6 @@ declare function batchUpdates(updates: () => void): Promise<void>;
|
|
|
55
60
|
/** Get some data from the store */
|
|
56
61
|
declare function get<TKey extends OnyxKey, TValue extends OnyxValue<TKey>>(key: TKey): Promise<TValue>;
|
|
57
62
|
declare function multiGet<TKey extends OnyxKey>(keys: CollectionKeyBase[]): Promise<Map<OnyxKey, OnyxValue<TKey>>>;
|
|
58
|
-
/**
|
|
59
|
-
* Stores a connection ID associated with a given key.
|
|
60
|
-
*
|
|
61
|
-
* @param connectionID - a connection ID of the subscriber
|
|
62
|
-
* @param key - a key that the subscriber is connected to
|
|
63
|
-
*/
|
|
64
|
-
declare function storeKeyByConnections(key: OnyxKey, connectionID: number): void;
|
|
65
|
-
/**
|
|
66
|
-
* Deletes a connection ID associated with its corresponding key.
|
|
67
|
-
*
|
|
68
|
-
* @param {number} connectionID - The connection ID to be deleted.
|
|
69
|
-
*/
|
|
70
|
-
declare function deleteKeyByConnections(connectionID: number): void;
|
|
71
63
|
/** Returns current key names stored in persisted storage */
|
|
72
64
|
declare function getAllKeys(): Promise<Set<OnyxKey>>;
|
|
73
65
|
/**
|
|
@@ -109,7 +101,7 @@ declare function getCollectionKey(key: OnyxKey): string;
|
|
|
109
101
|
* Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
|
|
110
102
|
* If the requested key is a collection, it will return an object with all the collection members.
|
|
111
103
|
*/
|
|
112
|
-
declare function tryGetCachedValue<TKey extends OnyxKey>(key: TKey, mapping?: Partial<
|
|
104
|
+
declare function tryGetCachedValue<TKey extends OnyxKey>(key: TKey, mapping?: Partial<Mapping<TKey>>): OnyxValue<OnyxKey>;
|
|
113
105
|
/**
|
|
114
106
|
* Remove a key from the recently accessed key list.
|
|
115
107
|
*/
|
|
@@ -120,13 +112,6 @@ declare function removeLastAccessedKey(key: OnyxKey): void;
|
|
|
120
112
|
* recently accessed key at the tail.
|
|
121
113
|
*/
|
|
122
114
|
declare function addLastAccessedKey(key: OnyxKey): void;
|
|
123
|
-
/**
|
|
124
|
-
* Removes a key previously added to this list
|
|
125
|
-
* which will enable it to be deleted again.
|
|
126
|
-
*/
|
|
127
|
-
declare function removeFromEvictionBlockList(key: OnyxKey, connectionID: number): void;
|
|
128
|
-
/** Keys added to this list can never be deleted. */
|
|
129
|
-
declare function addToEvictionBlockList(key: OnyxKey, connectionID: number): void;
|
|
130
115
|
/**
|
|
131
116
|
* Take all the keys that are safe to evict and add them to
|
|
132
117
|
* the recently accessed list when initializing the app. This
|
|
@@ -152,11 +137,6 @@ declare function keyChanged<TKey extends OnyxKey>(key: TKey, value: OnyxValue<TK
|
|
|
152
137
|
* - triggers the callback function
|
|
153
138
|
*/
|
|
154
139
|
declare function sendDataToConnection<TKey extends OnyxKey>(mapping: Mapping<TKey>, value: OnyxValue<TKey> | null, matchedKey: TKey | undefined, isBatched: boolean): void;
|
|
155
|
-
/**
|
|
156
|
-
* We check to see if this key is flagged as safe for eviction and add it to the recentlyAccessedKeys list so that when we
|
|
157
|
-
* run out of storage the least recently accessed key can be removed.
|
|
158
|
-
*/
|
|
159
|
-
declare function addKeyToRecentlyAccessedIfNeeded<TKey extends OnyxKey>(mapping: Mapping<TKey>): void;
|
|
160
140
|
/**
|
|
161
141
|
* Gets the data for a given an array of matching keys, combines them into an object, and sends the result back to the subscriber.
|
|
162
142
|
*/
|
|
@@ -228,6 +208,19 @@ declare function isValidNonEmptyCollectionForMerge<TKey extends CollectionKeyBas
|
|
|
228
208
|
* Verify if all the collection keys belong to the same parent
|
|
229
209
|
*/
|
|
230
210
|
declare function doAllCollectionItemsBelongToSameParent<TKey extends CollectionKeyBase>(collectionKey: TKey, collectionKeys: string[]): boolean;
|
|
211
|
+
/**
|
|
212
|
+
* Subscribes to an Onyx key and listens to its changes.
|
|
213
|
+
*
|
|
214
|
+
* @param connectOptions The options object that will define the behavior of the connection.
|
|
215
|
+
* @returns The subscription ID to use when calling `OnyxUtils.unsubscribeFromKey()`.
|
|
216
|
+
*/
|
|
217
|
+
declare function subscribeToKey<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKey>): number;
|
|
218
|
+
/**
|
|
219
|
+
* Disconnects and removes the listener from the Onyx key.
|
|
220
|
+
*
|
|
221
|
+
* @param subscriptionID Subscription ID returned by calling `OnyxUtils.subscribeToKey()`.
|
|
222
|
+
*/
|
|
223
|
+
declare function unsubscribeFromKey(subscriptionID: number): void;
|
|
231
224
|
declare const OnyxUtils: {
|
|
232
225
|
METHOD: {
|
|
233
226
|
readonly SET: "set";
|
|
@@ -238,8 +231,8 @@ declare const OnyxUtils: {
|
|
|
238
231
|
};
|
|
239
232
|
getMergeQueue: typeof getMergeQueue;
|
|
240
233
|
getMergeQueuePromise: typeof getMergeQueuePromise;
|
|
241
|
-
getCallbackToStateMapping: typeof getCallbackToStateMapping;
|
|
242
234
|
getDefaultKeyStates: typeof getDefaultKeyStates;
|
|
235
|
+
getDeferredInitTask: typeof getDeferredInitTask;
|
|
243
236
|
initStoreValues: typeof initStoreValues;
|
|
244
237
|
sendActionToDevTools: typeof sendActionToDevTools;
|
|
245
238
|
maybeFlushBatchUpdates: typeof maybeFlushBatchUpdates;
|
|
@@ -255,14 +248,11 @@ declare const OnyxUtils: {
|
|
|
255
248
|
tryGetCachedValue: typeof tryGetCachedValue;
|
|
256
249
|
removeLastAccessedKey: typeof removeLastAccessedKey;
|
|
257
250
|
addLastAccessedKey: typeof addLastAccessedKey;
|
|
258
|
-
removeFromEvictionBlockList: typeof removeFromEvictionBlockList;
|
|
259
|
-
addToEvictionBlockList: typeof addToEvictionBlockList;
|
|
260
251
|
addAllSafeEvictionKeysToRecentlyAccessedList: typeof addAllSafeEvictionKeysToRecentlyAccessedList;
|
|
261
252
|
getCachedCollection: typeof getCachedCollection;
|
|
262
253
|
keysChanged: typeof keysChanged;
|
|
263
254
|
keyChanged: typeof keyChanged;
|
|
264
255
|
sendDataToConnection: typeof sendDataToConnection;
|
|
265
|
-
addKeyToRecentlyAccessedIfNeeded: typeof addKeyToRecentlyAccessedIfNeeded;
|
|
266
256
|
getCollectionKey: typeof getCollectionKey;
|
|
267
257
|
getCollectionDataAndSendAsObject: typeof getCollectionDataAndSendAsObject;
|
|
268
258
|
scheduleSubscriberUpdate: typeof scheduleSubscriberUpdate;
|
|
@@ -276,11 +266,12 @@ declare const OnyxUtils: {
|
|
|
276
266
|
prepareKeyValuePairsForStorage: typeof prepareKeyValuePairsForStorage;
|
|
277
267
|
applyMerge: typeof applyMerge;
|
|
278
268
|
initializeWithDefaultKeyStates: typeof initializeWithDefaultKeyStates;
|
|
279
|
-
storeKeyByConnections: typeof storeKeyByConnections;
|
|
280
|
-
deleteKeyByConnections: typeof deleteKeyByConnections;
|
|
281
269
|
getSnapshotKey: typeof getSnapshotKey;
|
|
282
270
|
multiGet: typeof multiGet;
|
|
283
271
|
isValidNonEmptyCollectionForMerge: typeof isValidNonEmptyCollectionForMerge;
|
|
284
272
|
doAllCollectionItemsBelongToSameParent: typeof doAllCollectionItemsBelongToSameParent;
|
|
273
|
+
subscribeToKey: typeof subscribeToKey;
|
|
274
|
+
unsubscribeFromKey: typeof unsubscribeFromKey;
|
|
275
|
+
getEvictionBlocklist: typeof getEvictionBlocklist;
|
|
285
276
|
};
|
|
286
277
|
export default OnyxUtils;
|
package/dist/OnyxUtils.js
CHANGED
|
@@ -38,6 +38,7 @@ const Str = __importStar(require("./Str"));
|
|
|
38
38
|
const batch_1 = __importDefault(require("./batch"));
|
|
39
39
|
const storage_1 = __importDefault(require("./storage"));
|
|
40
40
|
const utils_1 = __importDefault(require("./utils"));
|
|
41
|
+
const createDeferredTask_1 = __importDefault(require("./createDeferredTask"));
|
|
41
42
|
// Method constants
|
|
42
43
|
const METHOD = {
|
|
43
44
|
SET: 'set',
|
|
@@ -53,14 +54,14 @@ const mergeQueuePromise = {};
|
|
|
53
54
|
const callbackToStateMapping = {};
|
|
54
55
|
// Keeps a copy of the values of the onyx collection keys as a map for faster lookups
|
|
55
56
|
let onyxCollectionKeySet = new Set();
|
|
56
|
-
// Holds a mapping of the connected key to the
|
|
57
|
-
const
|
|
57
|
+
// Holds a mapping of the connected key to the subscriptionID for faster lookups
|
|
58
|
+
const onyxKeyToSubscriptionIDs = new Map();
|
|
58
59
|
// Holds a list of keys that have been directly subscribed to or recently modified from least to most recent
|
|
59
60
|
let recentlyAccessedKeys = [];
|
|
60
61
|
// Holds a list of keys that are safe to remove when we reach max storage. If a key does not match with
|
|
61
62
|
// whatever appears in this list it will NEVER be a candidate for eviction.
|
|
62
63
|
let evictionAllowList = [];
|
|
63
|
-
// Holds a map of keys and
|
|
64
|
+
// Holds a map of keys and connection arrays whose keys will never be automatically evicted as
|
|
64
65
|
// long as we have at least one subscriber that returns false for the canEvict property.
|
|
65
66
|
const evictionBlocklist = {};
|
|
66
67
|
// Optional user-provided key value states set when Onyx initializes or clears
|
|
@@ -70,6 +71,10 @@ let batchUpdatesQueue = [];
|
|
|
70
71
|
// Used for comparison with a new update to avoid invoking the Onyx.connect callback with the same data.
|
|
71
72
|
const lastConnectionCallbackData = new Map();
|
|
72
73
|
let snapshotKey = null;
|
|
74
|
+
// Keeps track of the last subscriptionID that was used so we can keep incrementing it
|
|
75
|
+
let lastSubscriptionID = 0;
|
|
76
|
+
// Connections can be made before `Onyx.init`. They would wait for this task before resolving
|
|
77
|
+
const deferredInitTask = (0, createDeferredTask_1.default)();
|
|
73
78
|
function getSnapshotKey() {
|
|
74
79
|
return snapshotKey;
|
|
75
80
|
}
|
|
@@ -85,18 +90,24 @@ function getMergeQueue() {
|
|
|
85
90
|
function getMergeQueuePromise() {
|
|
86
91
|
return mergeQueuePromise;
|
|
87
92
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Getter - returns the callback to state mapping.
|
|
90
|
-
*/
|
|
91
|
-
function getCallbackToStateMapping() {
|
|
92
|
-
return callbackToStateMapping;
|
|
93
|
-
}
|
|
94
93
|
/**
|
|
95
94
|
* Getter - returns the default key states.
|
|
96
95
|
*/
|
|
97
96
|
function getDefaultKeyStates() {
|
|
98
97
|
return defaultKeyStates;
|
|
99
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Getter - returns the deffered init task.
|
|
101
|
+
*/
|
|
102
|
+
function getDeferredInitTask() {
|
|
103
|
+
return deferredInitTask;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Getter - returns the eviction block list.
|
|
107
|
+
*/
|
|
108
|
+
function getEvictionBlocklist() {
|
|
109
|
+
return evictionBlocklist;
|
|
110
|
+
}
|
|
100
111
|
/**
|
|
101
112
|
* Sets the initial values for the Onyx store
|
|
102
113
|
*
|
|
@@ -258,29 +269,29 @@ function multiGet(keys) {
|
|
|
258
269
|
}));
|
|
259
270
|
}
|
|
260
271
|
/**
|
|
261
|
-
* Stores a
|
|
272
|
+
* Stores a subscription ID associated with a given key.
|
|
262
273
|
*
|
|
263
|
-
* @param
|
|
264
|
-
* @param key -
|
|
274
|
+
* @param subscriptionID - A subscription ID of the subscriber.
|
|
275
|
+
* @param key - A key that the subscriber is subscribed to.
|
|
265
276
|
*/
|
|
266
|
-
function
|
|
267
|
-
if (!
|
|
268
|
-
|
|
277
|
+
function storeKeyBySubscriptions(key, subscriptionID) {
|
|
278
|
+
if (!onyxKeyToSubscriptionIDs.has(key)) {
|
|
279
|
+
onyxKeyToSubscriptionIDs.set(key, []);
|
|
269
280
|
}
|
|
270
|
-
|
|
281
|
+
onyxKeyToSubscriptionIDs.get(key).push(subscriptionID);
|
|
271
282
|
}
|
|
272
283
|
/**
|
|
273
|
-
* Deletes a
|
|
284
|
+
* Deletes a subscription ID associated with its corresponding key.
|
|
274
285
|
*
|
|
275
|
-
* @param
|
|
286
|
+
* @param subscriptionID - The subscription ID to be deleted.
|
|
276
287
|
*/
|
|
277
|
-
function
|
|
278
|
-
const subscriber = callbackToStateMapping[
|
|
279
|
-
if (subscriber &&
|
|
280
|
-
const
|
|
281
|
-
|
|
288
|
+
function deleteKeyBySubscriptions(subscriptionID) {
|
|
289
|
+
const subscriber = callbackToStateMapping[subscriptionID];
|
|
290
|
+
if (subscriber && onyxKeyToSubscriptionIDs.has(subscriber.key)) {
|
|
291
|
+
const updatedSubscriptionsIDs = onyxKeyToSubscriptionIDs.get(subscriber.key).filter((id) => id !== subscriptionID);
|
|
292
|
+
onyxKeyToSubscriptionIDs.set(subscriber.key, updatedSubscriptionsIDs);
|
|
282
293
|
}
|
|
283
|
-
lastConnectionCallbackData.delete(
|
|
294
|
+
lastConnectionCallbackData.delete(subscriptionID);
|
|
284
295
|
}
|
|
285
296
|
/** Returns current key names stored in persisted storage */
|
|
286
297
|
function getAllKeys() {
|
|
@@ -411,26 +422,6 @@ function addLastAccessedKey(key) {
|
|
|
411
422
|
removeLastAccessedKey(key);
|
|
412
423
|
recentlyAccessedKeys.push(key);
|
|
413
424
|
}
|
|
414
|
-
/**
|
|
415
|
-
* Removes a key previously added to this list
|
|
416
|
-
* which will enable it to be deleted again.
|
|
417
|
-
*/
|
|
418
|
-
function removeFromEvictionBlockList(key, connectionID) {
|
|
419
|
-
var _a, _b, _c;
|
|
420
|
-
evictionBlocklist[key] = (_b = (_a = evictionBlocklist[key]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== connectionID)) !== null && _b !== void 0 ? _b : [];
|
|
421
|
-
// Remove the key if there are no more subscribers
|
|
422
|
-
if (((_c = evictionBlocklist[key]) === null || _c === void 0 ? void 0 : _c.length) === 0) {
|
|
423
|
-
delete evictionBlocklist[key];
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
/** Keys added to this list can never be deleted. */
|
|
427
|
-
function addToEvictionBlockList(key, connectionID) {
|
|
428
|
-
removeFromEvictionBlockList(key, connectionID);
|
|
429
|
-
if (!evictionBlocklist[key]) {
|
|
430
|
-
evictionBlocklist[key] = [];
|
|
431
|
-
}
|
|
432
|
-
evictionBlocklist[key].push(connectionID);
|
|
433
|
-
}
|
|
434
425
|
/**
|
|
435
426
|
* Take all the keys that are safe to evict and add them to
|
|
436
427
|
* the recently accessed list when initializing the app. This
|
|
@@ -508,7 +499,7 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
508
499
|
// send the whole cached collection.
|
|
509
500
|
if (isSubscribedToCollectionKey) {
|
|
510
501
|
if (subscriber.waitForCollectionCallback) {
|
|
511
|
-
subscriber.callback(cachedCollection);
|
|
502
|
+
subscriber.callback(cachedCollection, subscriber.key);
|
|
512
503
|
continue;
|
|
513
504
|
}
|
|
514
505
|
// If they are not using waitForCollectionCallback then we notify the subscriber with
|
|
@@ -536,7 +527,7 @@ function keysChanged(collectionKey, partialCollection, partialPreviousCollection
|
|
|
536
527
|
continue;
|
|
537
528
|
}
|
|
538
529
|
// React component subscriber found.
|
|
539
|
-
if (
|
|
530
|
+
if (utils_1.default.hasWithOnyxInstance(subscriber)) {
|
|
540
531
|
if (!notifyWithOnyxSubscibers) {
|
|
541
532
|
continue;
|
|
542
533
|
}
|
|
@@ -647,12 +638,12 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
647
638
|
// Given the amount of times this function is called we need to make sure we are not iterating over all subscribers every time. On the other hand, we don't need to
|
|
648
639
|
// do the same in keysChanged, because we only call that function when a collection key changes, and it doesn't happen that often.
|
|
649
640
|
// For performance reason, we look for the given key and later if don't find it we look for the collection key, instead of checking if it is a collection key first.
|
|
650
|
-
let stateMappingKeys = (_a =
|
|
641
|
+
let stateMappingKeys = (_a = onyxKeyToSubscriptionIDs.get(key)) !== null && _a !== void 0 ? _a : [];
|
|
651
642
|
const collectionKey = getCollectionKey(key);
|
|
652
643
|
const plainCollectionKey = collectionKey.lastIndexOf('_') !== -1 ? collectionKey : undefined;
|
|
653
644
|
if (plainCollectionKey) {
|
|
654
645
|
// Getting the collection key from the specific key because only collection keys were stored in the mapping.
|
|
655
|
-
stateMappingKeys = [...stateMappingKeys, ...((_b =
|
|
646
|
+
stateMappingKeys = [...stateMappingKeys, ...((_b = onyxKeyToSubscriptionIDs.get(plainCollectionKey)) !== null && _b !== void 0 ? _b : [])];
|
|
656
647
|
if (stateMappingKeys.length === 0) {
|
|
657
648
|
return;
|
|
658
649
|
}
|
|
@@ -668,7 +659,7 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
668
659
|
if (!notifyConnectSubscribers) {
|
|
669
660
|
continue;
|
|
670
661
|
}
|
|
671
|
-
if (lastConnectionCallbackData.has(subscriber.
|
|
662
|
+
if (lastConnectionCallbackData.has(subscriber.subscriptionID) && lastConnectionCallbackData.get(subscriber.subscriptionID) === value) {
|
|
672
663
|
continue;
|
|
673
664
|
}
|
|
674
665
|
if (isCollectionKey(subscriber.key) && subscriber.waitForCollectionCallback) {
|
|
@@ -678,16 +669,16 @@ function keyChanged(key, value, previousValue, canUpdateSubscriber = () => true,
|
|
|
678
669
|
cachedCollections[subscriber.key] = cachedCollection;
|
|
679
670
|
}
|
|
680
671
|
cachedCollection[key] = value;
|
|
681
|
-
subscriber.callback(cachedCollection);
|
|
672
|
+
subscriber.callback(cachedCollection, subscriber.key);
|
|
682
673
|
continue;
|
|
683
674
|
}
|
|
684
675
|
const subscriberCallback = subscriber.callback;
|
|
685
676
|
subscriberCallback(value, key);
|
|
686
|
-
lastConnectionCallbackData.set(subscriber.
|
|
677
|
+
lastConnectionCallbackData.set(subscriber.subscriptionID, value);
|
|
687
678
|
continue;
|
|
688
679
|
}
|
|
689
680
|
// Subscriber connected via withOnyx() HOC
|
|
690
|
-
if (
|
|
681
|
+
if (utils_1.default.hasWithOnyxInstance(subscriber)) {
|
|
691
682
|
if (!notifyWithOnyxSubscribers) {
|
|
692
683
|
continue;
|
|
693
684
|
}
|
|
@@ -770,10 +761,10 @@ function sendDataToConnection(mapping, value, matchedKey, isBatched) {
|
|
|
770
761
|
var _a, _b;
|
|
771
762
|
// If the mapping no longer exists then we should not send any data.
|
|
772
763
|
// This means our subscriber disconnected or withOnyx wrapped component unmounted.
|
|
773
|
-
if (!callbackToStateMapping[mapping.
|
|
764
|
+
if (!callbackToStateMapping[mapping.subscriptionID]) {
|
|
774
765
|
return;
|
|
775
766
|
}
|
|
776
|
-
if (
|
|
767
|
+
if (utils_1.default.hasWithOnyxInstance(mapping)) {
|
|
777
768
|
let newData = value;
|
|
778
769
|
// If the mapping has a selector, then the component's state must only be updated with the data
|
|
779
770
|
// returned by the selector.
|
|
@@ -801,10 +792,10 @@ function sendDataToConnection(mapping, value, matchedKey, isBatched) {
|
|
|
801
792
|
// withOnyx will internally replace null values with undefined and never pass null values to wrapped components.
|
|
802
793
|
// For regular callbacks, we never want to pass null values, but always just undefined if a value is not set in cache or storage.
|
|
803
794
|
const valueToPass = value === null ? undefined : value;
|
|
804
|
-
const lastValue = lastConnectionCallbackData.get(mapping.
|
|
805
|
-
lastConnectionCallbackData.get(mapping.
|
|
795
|
+
const lastValue = lastConnectionCallbackData.get(mapping.subscriptionID);
|
|
796
|
+
lastConnectionCallbackData.get(mapping.subscriptionID);
|
|
806
797
|
// If the value has not changed we do not need to trigger the callback
|
|
807
|
-
if (lastConnectionCallbackData.has(mapping.
|
|
798
|
+
if (lastConnectionCallbackData.has(mapping.subscriptionID) && valueToPass === lastValue) {
|
|
808
799
|
return;
|
|
809
800
|
}
|
|
810
801
|
(_b = (_a = mapping).callback) === null || _b === void 0 ? void 0 : _b.call(_a, valueToPass, matchedKey);
|
|
@@ -819,7 +810,7 @@ function addKeyToRecentlyAccessedIfNeeded(mapping) {
|
|
|
819
810
|
}
|
|
820
811
|
// Try to free some cache whenever we connect to a safe eviction key
|
|
821
812
|
OnyxCache_1.default.removeLeastRecentlyUsedKeys();
|
|
822
|
-
if (
|
|
813
|
+
if (utils_1.default.hasWithOnyxInstance(mapping) && !isCollectionKey(mapping.key)) {
|
|
823
814
|
// All React components subscribing to a key flagged as a safe eviction key must implement the canEvict property.
|
|
824
815
|
if (mapping.canEvict === undefined) {
|
|
825
816
|
throw new Error(`Cannot subscribe to safe eviction key '${mapping.key}' without providing a canEvict value.`);
|
|
@@ -996,7 +987,7 @@ function isValidNonEmptyCollectionForMerge(collection) {
|
|
|
996
987
|
function doAllCollectionItemsBelongToSameParent(collectionKey, collectionKeys) {
|
|
997
988
|
let hasCollectionKeyCheckFailed = false;
|
|
998
989
|
collectionKeys.forEach((dataKey) => {
|
|
999
|
-
if (
|
|
990
|
+
if (isKeyMatch(collectionKey, dataKey)) {
|
|
1000
991
|
return;
|
|
1001
992
|
}
|
|
1002
993
|
if (process.env.NODE_ENV === 'development') {
|
|
@@ -1007,12 +998,116 @@ function doAllCollectionItemsBelongToSameParent(collectionKey, collectionKeys) {
|
|
|
1007
998
|
});
|
|
1008
999
|
return !hasCollectionKeyCheckFailed;
|
|
1009
1000
|
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Subscribes to an Onyx key and listens to its changes.
|
|
1003
|
+
*
|
|
1004
|
+
* @param connectOptions The options object that will define the behavior of the connection.
|
|
1005
|
+
* @returns The subscription ID to use when calling `OnyxUtils.unsubscribeFromKey()`.
|
|
1006
|
+
*/
|
|
1007
|
+
function subscribeToKey(connectOptions) {
|
|
1008
|
+
const mapping = connectOptions;
|
|
1009
|
+
const subscriptionID = lastSubscriptionID++;
|
|
1010
|
+
callbackToStateMapping[subscriptionID] = mapping;
|
|
1011
|
+
callbackToStateMapping[subscriptionID].subscriptionID = subscriptionID;
|
|
1012
|
+
// When keyChanged is called, a key is passed and the method looks through all the Subscribers in callbackToStateMapping for the matching key to get the subscriptionID
|
|
1013
|
+
// to avoid having to loop through all the Subscribers all the time (even when just one connection belongs to one key),
|
|
1014
|
+
// We create a mapping from key to lists of subscriptionIDs to access the specific list of subscriptionIDs.
|
|
1015
|
+
storeKeyBySubscriptions(mapping.key, callbackToStateMapping[subscriptionID].subscriptionID);
|
|
1016
|
+
if (mapping.initWithStoredValues === false) {
|
|
1017
|
+
return subscriptionID;
|
|
1018
|
+
}
|
|
1019
|
+
// Commit connection only after init passes
|
|
1020
|
+
deferredInitTask.promise
|
|
1021
|
+
.then(() => addKeyToRecentlyAccessedIfNeeded(mapping))
|
|
1022
|
+
.then(() => {
|
|
1023
|
+
// Performance improvement
|
|
1024
|
+
// If the mapping is connected to an onyx key that is not a collection
|
|
1025
|
+
// we can skip the call to getAllKeys() and return an array with a single item
|
|
1026
|
+
if (Boolean(mapping.key) && typeof mapping.key === 'string' && !mapping.key.endsWith('_') && OnyxCache_1.default.getAllKeys().has(mapping.key)) {
|
|
1027
|
+
return new Set([mapping.key]);
|
|
1028
|
+
}
|
|
1029
|
+
return getAllKeys();
|
|
1030
|
+
})
|
|
1031
|
+
.then((keys) => {
|
|
1032
|
+
// We search all the keys in storage to see if any are a "match" for the subscriber we are connecting so that we
|
|
1033
|
+
// can send data back to the subscriber. Note that multiple keys can match as a subscriber could either be
|
|
1034
|
+
// subscribed to a "collection key" or a single key.
|
|
1035
|
+
const matchingKeys = [];
|
|
1036
|
+
keys.forEach((key) => {
|
|
1037
|
+
if (!isKeyMatch(mapping.key, key)) {
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
matchingKeys.push(key);
|
|
1041
|
+
});
|
|
1042
|
+
// If the key being connected to does not exist we initialize the value with null. For subscribers that connected
|
|
1043
|
+
// directly via connect() they will simply get a null value sent to them without any information about which key matched
|
|
1044
|
+
// since there are none matched. In withOnyx() we wait for all connected keys to return a value before rendering the child
|
|
1045
|
+
// component. This null value will be filtered out so that the connected component can utilize defaultProps.
|
|
1046
|
+
if (matchingKeys.length === 0) {
|
|
1047
|
+
if (mapping.key && !isCollectionKey(mapping.key)) {
|
|
1048
|
+
OnyxCache_1.default.addNullishStorageKey(mapping.key);
|
|
1049
|
+
}
|
|
1050
|
+
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
|
|
1051
|
+
// or they will be undefined.
|
|
1052
|
+
sendDataToConnection(mapping, null, undefined, false);
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
// When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
|
|
1056
|
+
// into an object and just make a single call. The latter behavior is enabled by providing a waitForCollectionCallback key
|
|
1057
|
+
// combined with a subscription to a collection key.
|
|
1058
|
+
if (typeof mapping.callback === 'function') {
|
|
1059
|
+
if (isCollectionKey(mapping.key)) {
|
|
1060
|
+
if (mapping.waitForCollectionCallback) {
|
|
1061
|
+
getCollectionDataAndSendAsObject(matchingKeys, mapping);
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
// We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
|
|
1065
|
+
multiGet(matchingKeys).then((values) => {
|
|
1066
|
+
values.forEach((val, key) => {
|
|
1067
|
+
sendDataToConnection(mapping, val, key, true);
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
// If we are not subscribed to a collection key then there's only a single key to send an update for.
|
|
1073
|
+
get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key, true));
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
// If we have a withOnyxInstance that means a React component has subscribed via the withOnyx() HOC and we need to
|
|
1077
|
+
// group collection key member data into an object.
|
|
1078
|
+
if (utils_1.default.hasWithOnyxInstance(mapping)) {
|
|
1079
|
+
if (isCollectionKey(mapping.key)) {
|
|
1080
|
+
getCollectionDataAndSendAsObject(matchingKeys, mapping);
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
// If the subscriber is not using a collection key then we just send a single value back to the subscriber
|
|
1084
|
+
get(mapping.key).then((val) => sendDataToConnection(mapping, val, mapping.key, true));
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
console.error('Warning: Onyx.connect() was found without a callback or withOnyxInstance');
|
|
1088
|
+
});
|
|
1089
|
+
// The subscriptionID is returned back to the caller so that it can be used to clean up the connection when it's no longer needed
|
|
1090
|
+
// by calling OnyxUtils.unsubscribeFromKey(subscriptionID).
|
|
1091
|
+
return subscriptionID;
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Disconnects and removes the listener from the Onyx key.
|
|
1095
|
+
*
|
|
1096
|
+
* @param subscriptionID Subscription ID returned by calling `OnyxUtils.subscribeToKey()`.
|
|
1097
|
+
*/
|
|
1098
|
+
function unsubscribeFromKey(subscriptionID) {
|
|
1099
|
+
if (!callbackToStateMapping[subscriptionID]) {
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
deleteKeyBySubscriptions(lastSubscriptionID);
|
|
1103
|
+
delete callbackToStateMapping[subscriptionID];
|
|
1104
|
+
}
|
|
1010
1105
|
const OnyxUtils = {
|
|
1011
1106
|
METHOD,
|
|
1012
1107
|
getMergeQueue,
|
|
1013
1108
|
getMergeQueuePromise,
|
|
1014
|
-
getCallbackToStateMapping,
|
|
1015
1109
|
getDefaultKeyStates,
|
|
1110
|
+
getDeferredInitTask,
|
|
1016
1111
|
initStoreValues,
|
|
1017
1112
|
sendActionToDevTools,
|
|
1018
1113
|
maybeFlushBatchUpdates,
|
|
@@ -1028,14 +1123,11 @@ const OnyxUtils = {
|
|
|
1028
1123
|
tryGetCachedValue,
|
|
1029
1124
|
removeLastAccessedKey,
|
|
1030
1125
|
addLastAccessedKey,
|
|
1031
|
-
removeFromEvictionBlockList,
|
|
1032
|
-
addToEvictionBlockList,
|
|
1033
1126
|
addAllSafeEvictionKeysToRecentlyAccessedList,
|
|
1034
1127
|
getCachedCollection,
|
|
1035
1128
|
keysChanged,
|
|
1036
1129
|
keyChanged,
|
|
1037
1130
|
sendDataToConnection,
|
|
1038
|
-
addKeyToRecentlyAccessedIfNeeded,
|
|
1039
1131
|
getCollectionKey,
|
|
1040
1132
|
getCollectionDataAndSendAsObject,
|
|
1041
1133
|
scheduleSubscriberUpdate,
|
|
@@ -1049,11 +1141,12 @@ const OnyxUtils = {
|
|
|
1049
1141
|
prepareKeyValuePairsForStorage,
|
|
1050
1142
|
applyMerge,
|
|
1051
1143
|
initializeWithDefaultKeyStates,
|
|
1052
|
-
storeKeyByConnections,
|
|
1053
|
-
deleteKeyByConnections,
|
|
1054
1144
|
getSnapshotKey,
|
|
1055
1145
|
multiGet,
|
|
1056
1146
|
isValidNonEmptyCollectionForMerge,
|
|
1057
1147
|
doAllCollectionItemsBelongToSameParent,
|
|
1148
|
+
subscribeToKey,
|
|
1149
|
+
unsubscribeFromKey,
|
|
1150
|
+
getEvictionBlocklist,
|
|
1058
1151
|
};
|
|
1059
1152
|
exports.default = OnyxUtils;
|
package/dist/Str.d.ts
CHANGED
|
@@ -14,4 +14,8 @@ declare function startsWith(haystack: string, needle: string): boolean;
|
|
|
14
14
|
*/
|
|
15
15
|
declare function result(parameter: string): string;
|
|
16
16
|
declare function result<TFunction extends (...a: TArgs) => unknown, TArgs extends unknown[]>(parameter: TFunction, ...args: TArgs): ReturnType<TFunction>;
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* A simple GUID generator taken from https://stackoverflow.com/a/32760401/9114791
|
|
19
|
+
*/
|
|
20
|
+
declare function guid(): string;
|
|
21
|
+
export { guid, result, startsWith };
|
package/dist/Str.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.result = exports.
|
|
3
|
+
exports.startsWith = exports.result = exports.guid = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Returns true if the haystack begins with the needle
|
|
6
6
|
*
|
|
@@ -16,3 +16,15 @@ function result(parameter, ...args) {
|
|
|
16
16
|
return typeof parameter === 'function' ? parameter(...args) : parameter;
|
|
17
17
|
}
|
|
18
18
|
exports.result = result;
|
|
19
|
+
/**
|
|
20
|
+
* A simple GUID generator taken from https://stackoverflow.com/a/32760401/9114791
|
|
21
|
+
*/
|
|
22
|
+
function guid() {
|
|
23
|
+
function s4() {
|
|
24
|
+
return Math.floor((1 + Math.random()) * 0x10000)
|
|
25
|
+
.toString(16)
|
|
26
|
+
.substring(1);
|
|
27
|
+
}
|
|
28
|
+
return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;
|
|
29
|
+
}
|
|
30
|
+
exports.guid = guid;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import type { ConnectOptions, OnyxUpdate } from './Onyx';
|
|
|
2
2
|
import Onyx from './Onyx';
|
|
3
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
|
+
import type { Connection } from './OnyxConnectionManager';
|
|
5
6
|
import useOnyx from './useOnyx';
|
|
6
7
|
import withOnyx from './withOnyx';
|
|
7
8
|
import type { WithOnyxState } from './withOnyx/types';
|
|
8
9
|
export default Onyx;
|
|
9
10
|
export { useOnyx, withOnyx };
|
|
10
|
-
export type { ConnectOptions, CustomTypeOptions, FetchStatus, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, ResultMetadata, Selector, UseOnyxResult, WithOnyxState, };
|
|
11
|
+
export type { ConnectOptions, CustomTypeOptions, FetchStatus, KeyValueMapping, NullishDeep, OnyxCollection, OnyxEntry, OnyxKey, OnyxInputValue, OnyxCollectionInputValue, OnyxInput, OnyxSetInput, OnyxMultiSetInput, OnyxMergeInput, OnyxMergeCollectionInput, OnyxUpdate, OnyxValue, ResultMetadata, Selector, UseOnyxResult, WithOnyxState, Connection, };
|