react-native-onyx 2.0.63 → 2.0.65
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 +34 -128
- package/dist/OnyxConnectionManager.d.ts +69 -0
- package/dist/OnyxConnectionManager.js +195 -0
- package/dist/OnyxUtils.d.ts +29 -38
- package/dist/OnyxUtils.js +161 -66
- 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/API.md
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
<dt><a href="#init">init()</a></dt>
|
|
9
9
|
<dd><p>Initialize the store with actions and listening for storage events</p>
|
|
10
10
|
</dd>
|
|
11
|
-
<dt><a href="#connect">connect(
|
|
12
|
-
<dd><p>
|
|
11
|
+
<dt><a href="#connect">connect(connectOptions)</a> ⇒</dt>
|
|
12
|
+
<dd><p>Connects to an Onyx key given the options passed and listens to its changes.</p>
|
|
13
13
|
</dd>
|
|
14
|
-
<dt><a href="#disconnect">disconnect(
|
|
15
|
-
<dd><p>
|
|
14
|
+
<dt><a href="#disconnect">disconnect(connection)</a></dt>
|
|
15
|
+
<dd><p>Disconnects and removes the listener from the Onyx key.</p>
|
|
16
16
|
</dd>
|
|
17
17
|
<dt><a href="#set">set(key, value)</a></dt>
|
|
18
18
|
<dd><p>Write a value to our store with the given key</p>
|
|
@@ -60,45 +60,49 @@ Initialize the store with actions and listening for storage events
|
|
|
60
60
|
**Kind**: global function
|
|
61
61
|
<a name="connect"></a>
|
|
62
62
|
|
|
63
|
-
## connect(
|
|
64
|
-
|
|
63
|
+
## connect(connectOptions) ⇒
|
|
64
|
+
Connects to an Onyx key given the options passed and listens to its changes.
|
|
65
65
|
|
|
66
66
|
**Kind**: global function
|
|
67
|
-
**Returns**:
|
|
67
|
+
**Returns**: The connection object to use when calling `Onyx.disconnect()`.
|
|
68
68
|
|
|
69
69
|
| Param | Description |
|
|
70
70
|
| --- | --- |
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
| [mapping.initialValue] | THIS PARAM IS ONLY USED WITH withOnyx(). If included, this will be passed to the component so that something can be rendered while data is being fetched from the DB. Note that it will not cause the component to have the loading prop set to true. |
|
|
71
|
+
| connectOptions | The options object that will define the behavior of the connection. |
|
|
72
|
+
| connectOptions.key | The Onyx key to subscribe to. |
|
|
73
|
+
| connectOptions.callback | A function that will be called when the Onyx data we are subscribed changes. |
|
|
74
|
+
| connectOptions.waitForCollectionCallback | If set to `true`, it will return the entire collection to the callback as a single object. |
|
|
75
|
+
| connectOptions.withOnyxInstance | The `withOnyx` class instance to be internally passed. **Only used inside `withOnyx()` HOC.** |
|
|
76
|
+
| connectOptions.statePropertyName | The name of the component's prop that is connected to the Onyx key. **Only used inside `withOnyx()` HOC.** |
|
|
77
|
+
| connectOptions.displayName | The component's display name. **Only used inside `withOnyx()` HOC.** |
|
|
78
|
+
| connectOptions.selector | This will be used to subscribe to a subset of an Onyx key's data. **Only used inside `useOnyx()` hook or `withOnyx()` HOC.** Using this setting on `useOnyx()` or `withOnyx()` can have very positive performance benefits because the component will only re-render when the subset of data changes. Otherwise, any change of data on any property would normally cause the component to re-render (and that can be expensive from a performance standpoint). |
|
|
80
79
|
|
|
81
80
|
**Example**
|
|
82
|
-
```
|
|
83
|
-
const
|
|
81
|
+
```ts
|
|
82
|
+
const connection = Onyx.connect({
|
|
84
83
|
key: ONYXKEYS.SESSION,
|
|
85
84
|
callback: onSessionChange,
|
|
86
85
|
});
|
|
87
86
|
```
|
|
88
87
|
<a name="disconnect"></a>
|
|
89
88
|
|
|
90
|
-
## disconnect(
|
|
91
|
-
|
|
89
|
+
## disconnect(connection)
|
|
90
|
+
Disconnects and removes the listener from the Onyx key.
|
|
92
91
|
|
|
93
92
|
**Kind**: global function
|
|
94
93
|
|
|
95
94
|
| Param | Description |
|
|
96
95
|
| --- | --- |
|
|
97
|
-
|
|
|
96
|
+
| connection | Connection object returned by calling `Onyx.connect()`. |
|
|
98
97
|
|
|
99
98
|
**Example**
|
|
100
|
-
```
|
|
101
|
-
Onyx.
|
|
99
|
+
```ts
|
|
100
|
+
const connection = Onyx.connect({
|
|
101
|
+
key: ONYXKEYS.SESSION,
|
|
102
|
+
callback: onSessionChange,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
Onyx.disconnect(connection);
|
|
102
106
|
```
|
|
103
107
|
<a name="set"></a>
|
|
104
108
|
|
package/dist/Onyx.d.ts
CHANGED
|
@@ -1,44 +1,49 @@
|
|
|
1
1
|
import * as Logger from './Logger';
|
|
2
2
|
import type { CollectionKeyBase, ConnectOptions, InitOptions, Mapping, OnyxKey, OnyxMergeCollectionInput, OnyxMergeInput, OnyxMultiSetInput, OnyxSetInput, OnyxUpdate } from './types';
|
|
3
|
+
import type { Connection } from './OnyxConnectionManager';
|
|
3
4
|
/** Initialize the store with actions and listening for storage events */
|
|
4
5
|
declare function init({ keys, initialKeyStates, safeEvictionKeys, maxCachedKeysCount, shouldSyncMultipleInstances, debugSetState, }: InitOptions): void;
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
7
8
|
*
|
|
8
9
|
* @example
|
|
9
|
-
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const connection = Onyx.connect({
|
|
10
12
|
* key: ONYXKEYS.SESSION,
|
|
11
13
|
* callback: onSessionChange,
|
|
12
14
|
* });
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
* @param
|
|
18
|
-
*
|
|
19
|
-
* @param
|
|
20
|
-
*
|
|
21
|
-
* @param
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* cause the component to re-render (and that can be expensive from a performance standpoint).
|
|
28
|
-
* @param [mapping.initialValue] THIS PARAM IS ONLY USED WITH withOnyx().
|
|
29
|
-
* If included, this will be passed to the component so that something can be rendered while data is being fetched from the DB.
|
|
30
|
-
* Note that it will not cause the component to have the loading prop set to true.
|
|
31
|
-
* @returns an ID to use when calling disconnect
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @param connectOptions The options object that will define the behavior of the connection.
|
|
18
|
+
* @param connectOptions.key The Onyx key to subscribe to.
|
|
19
|
+
* @param connectOptions.callback A function that will be called when the Onyx data we are subscribed changes.
|
|
20
|
+
* @param connectOptions.waitForCollectionCallback If set to `true`, it will return the entire collection to the callback as a single object.
|
|
21
|
+
* @param connectOptions.withOnyxInstance The `withOnyx` class instance to be internally passed. **Only used inside `withOnyx()` HOC.**
|
|
22
|
+
* @param connectOptions.statePropertyName The name of the component's prop that is connected to the Onyx key. **Only used inside `withOnyx()` HOC.**
|
|
23
|
+
* @param connectOptions.displayName The component's display name. **Only used inside `withOnyx()` HOC.**
|
|
24
|
+
* @param connectOptions.selector This will be used to subscribe to a subset of an Onyx key's data. **Only used inside `useOnyx()` hook or `withOnyx()` HOC.**
|
|
25
|
+
* Using this setting on `useOnyx()` or `withOnyx()` can have very positive performance benefits because the component will only re-render
|
|
26
|
+
* when the subset of data changes. Otherwise, any change of data on any property would normally
|
|
27
|
+
* cause the component to re-render (and that can be expensive from a performance standpoint).
|
|
28
|
+
* @returns The connection object to use when calling `Onyx.disconnect()`.
|
|
32
29
|
*/
|
|
33
|
-
declare function connect<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKey>):
|
|
30
|
+
declare function connect<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKey>): Connection;
|
|
34
31
|
/**
|
|
35
|
-
*
|
|
32
|
+
* Disconnects and removes the listener from the Onyx key.
|
|
33
|
+
*
|
|
36
34
|
* @example
|
|
37
|
-
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* const connection = Onyx.connect({
|
|
37
|
+
* key: ONYXKEYS.SESSION,
|
|
38
|
+
* callback: onSessionChange,
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* Onyx.disconnect(connection);
|
|
42
|
+
* ```
|
|
38
43
|
*
|
|
39
|
-
* @param
|
|
44
|
+
* @param connection Connection object returned by calling `Onyx.connect()`.
|
|
40
45
|
*/
|
|
41
|
-
declare function disconnect(
|
|
46
|
+
declare function disconnect(connection: Connection): void;
|
|
42
47
|
/**
|
|
43
48
|
* Write a value to our store with the given key
|
|
44
49
|
*
|
package/dist/Onyx.js
CHANGED
|
@@ -31,17 +31,13 @@ const underscore_1 = __importDefault(require("underscore"));
|
|
|
31
31
|
const pick_1 = __importDefault(require("lodash/pick"));
|
|
32
32
|
const Logger = __importStar(require("./Logger"));
|
|
33
33
|
const OnyxCache_1 = __importDefault(require("./OnyxCache"));
|
|
34
|
-
const createDeferredTask_1 = __importDefault(require("./createDeferredTask"));
|
|
35
34
|
const PerformanceUtils = __importStar(require("./PerformanceUtils"));
|
|
36
35
|
const storage_1 = __importDefault(require("./storage"));
|
|
37
36
|
const utils_1 = __importDefault(require("./utils"));
|
|
38
37
|
const DevTools_1 = __importDefault(require("./DevTools"));
|
|
39
38
|
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
40
39
|
const logMessages_1 = __importDefault(require("./logMessages"));
|
|
41
|
-
|
|
42
|
-
let lastConnectionID = 0;
|
|
43
|
-
// Connections can be made before `Onyx.init`. They would wait for this task before resolving
|
|
44
|
-
const deferredInitTask = (0, createDeferredTask_1.default)();
|
|
40
|
+
const OnyxConnectionManager_1 = __importDefault(require("./OnyxConnectionManager"));
|
|
45
41
|
/** Initialize the store with actions and listening for storage events */
|
|
46
42
|
function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCachedKeysCount = 1000, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, }) {
|
|
47
43
|
var _a;
|
|
@@ -61,142 +57,52 @@ function init({ keys = {}, initialKeyStates = {}, safeEvictionKeys = [], maxCach
|
|
|
61
57
|
}
|
|
62
58
|
OnyxUtils_1.default.initStoreValues(keys, initialKeyStates, safeEvictionKeys);
|
|
63
59
|
// Initialize all of our keys with data provided then give green light to any pending connections
|
|
64
|
-
Promise.all([OnyxUtils_1.default.addAllSafeEvictionKeysToRecentlyAccessedList(), OnyxUtils_1.default.initializeWithDefaultKeyStates()]).then(
|
|
60
|
+
Promise.all([OnyxUtils_1.default.addAllSafeEvictionKeysToRecentlyAccessedList(), OnyxUtils_1.default.initializeWithDefaultKeyStates()]).then(OnyxUtils_1.default.getDeferredInitTask().resolve);
|
|
65
61
|
}
|
|
66
62
|
/**
|
|
67
|
-
*
|
|
63
|
+
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
68
64
|
*
|
|
69
65
|
* @example
|
|
70
|
-
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* const connection = Onyx.connect({
|
|
71
68
|
* key: ONYXKEYS.SESSION,
|
|
72
69
|
* callback: onSessionChange,
|
|
73
70
|
* });
|
|
71
|
+
* ```
|
|
74
72
|
*
|
|
75
|
-
* @param
|
|
76
|
-
* @param
|
|
77
|
-
* @param
|
|
78
|
-
* @param
|
|
79
|
-
*
|
|
80
|
-
* @param
|
|
81
|
-
*
|
|
82
|
-
* @param
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* performance benefits because the component will only re-render when the subset of data changes. Otherwise, any change of data on any property would normally
|
|
88
|
-
* cause the component to re-render (and that can be expensive from a performance standpoint).
|
|
89
|
-
* @param [mapping.initialValue] THIS PARAM IS ONLY USED WITH withOnyx().
|
|
90
|
-
* If included, this will be passed to the component so that something can be rendered while data is being fetched from the DB.
|
|
91
|
-
* Note that it will not cause the component to have the loading prop set to true.
|
|
92
|
-
* @returns an ID to use when calling disconnect
|
|
73
|
+
* @param connectOptions The options object that will define the behavior of the connection.
|
|
74
|
+
* @param connectOptions.key The Onyx key to subscribe to.
|
|
75
|
+
* @param connectOptions.callback A function that will be called when the Onyx data we are subscribed changes.
|
|
76
|
+
* @param connectOptions.waitForCollectionCallback If set to `true`, it will return the entire collection to the callback as a single object.
|
|
77
|
+
* @param connectOptions.withOnyxInstance The `withOnyx` class instance to be internally passed. **Only used inside `withOnyx()` HOC.**
|
|
78
|
+
* @param connectOptions.statePropertyName The name of the component's prop that is connected to the Onyx key. **Only used inside `withOnyx()` HOC.**
|
|
79
|
+
* @param connectOptions.displayName The component's display name. **Only used inside `withOnyx()` HOC.**
|
|
80
|
+
* @param connectOptions.selector This will be used to subscribe to a subset of an Onyx key's data. **Only used inside `useOnyx()` hook or `withOnyx()` HOC.**
|
|
81
|
+
* Using this setting on `useOnyx()` or `withOnyx()` can have very positive performance benefits because the component will only re-render
|
|
82
|
+
* when the subset of data changes. Otherwise, any change of data on any property would normally
|
|
83
|
+
* cause the component to re-render (and that can be expensive from a performance standpoint).
|
|
84
|
+
* @returns The connection object to use when calling `Onyx.disconnect()`.
|
|
93
85
|
*/
|
|
94
86
|
function connect(connectOptions) {
|
|
95
|
-
|
|
96
|
-
const connectionID = lastConnectionID++;
|
|
97
|
-
const callbackToStateMapping = OnyxUtils_1.default.getCallbackToStateMapping();
|
|
98
|
-
callbackToStateMapping[connectionID] = mapping;
|
|
99
|
-
callbackToStateMapping[connectionID].connectionID = connectionID;
|
|
100
|
-
// 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 connectionID
|
|
101
|
-
// to avoid having to loop through all the Subscribers all the time (even when just one connection belongs to one key),
|
|
102
|
-
// We create a mapping from key to lists of connectionIDs to access the specific list of connectionIDs.
|
|
103
|
-
OnyxUtils_1.default.storeKeyByConnections(mapping.key, callbackToStateMapping[connectionID].connectionID);
|
|
104
|
-
if (mapping.initWithStoredValues === false) {
|
|
105
|
-
return connectionID;
|
|
106
|
-
}
|
|
107
|
-
// Commit connection only after init passes
|
|
108
|
-
deferredInitTask.promise
|
|
109
|
-
.then(() => OnyxUtils_1.default.addKeyToRecentlyAccessedIfNeeded(mapping))
|
|
110
|
-
.then(() => {
|
|
111
|
-
// Performance improvement
|
|
112
|
-
// If the mapping is connected to an onyx key that is not a collection
|
|
113
|
-
// we can skip the call to getAllKeys() and return an array with a single item
|
|
114
|
-
if (Boolean(mapping.key) && typeof mapping.key === 'string' && !mapping.key.endsWith('_') && OnyxCache_1.default.getAllKeys().has(mapping.key)) {
|
|
115
|
-
return new Set([mapping.key]);
|
|
116
|
-
}
|
|
117
|
-
return OnyxUtils_1.default.getAllKeys();
|
|
118
|
-
})
|
|
119
|
-
.then((keys) => {
|
|
120
|
-
// We search all the keys in storage to see if any are a "match" for the subscriber we are connecting so that we
|
|
121
|
-
// can send data back to the subscriber. Note that multiple keys can match as a subscriber could either be
|
|
122
|
-
// subscribed to a "collection key" or a single key.
|
|
123
|
-
const matchingKeys = [];
|
|
124
|
-
keys.forEach((key) => {
|
|
125
|
-
if (!OnyxUtils_1.default.isKeyMatch(mapping.key, key)) {
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
matchingKeys.push(key);
|
|
129
|
-
});
|
|
130
|
-
// If the key being connected to does not exist we initialize the value with null. For subscribers that connected
|
|
131
|
-
// directly via connect() they will simply get a null value sent to them without any information about which key matched
|
|
132
|
-
// since there are none matched. In withOnyx() we wait for all connected keys to return a value before rendering the child
|
|
133
|
-
// component. This null value will be filtered out so that the connected component can utilize defaultProps.
|
|
134
|
-
if (matchingKeys.length === 0) {
|
|
135
|
-
if (mapping.key && !OnyxUtils_1.default.isCollectionKey(mapping.key)) {
|
|
136
|
-
OnyxCache_1.default.addNullishStorageKey(mapping.key);
|
|
137
|
-
}
|
|
138
|
-
// Here we cannot use batching because the nullish value is expected to be set immediately for default props
|
|
139
|
-
// or they will be undefined.
|
|
140
|
-
OnyxUtils_1.default.sendDataToConnection(mapping, null, undefined, false);
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
// When using a callback subscriber we will either trigger the provided callback for each key we find or combine all values
|
|
144
|
-
// into an object and just make a single call. The latter behavior is enabled by providing a waitForCollectionCallback key
|
|
145
|
-
// combined with a subscription to a collection key.
|
|
146
|
-
if (typeof mapping.callback === 'function') {
|
|
147
|
-
if (OnyxUtils_1.default.isCollectionKey(mapping.key)) {
|
|
148
|
-
if (mapping.waitForCollectionCallback) {
|
|
149
|
-
OnyxUtils_1.default.getCollectionDataAndSendAsObject(matchingKeys, mapping);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
// We did not opt into using waitForCollectionCallback mode so the callback is called for every matching key.
|
|
153
|
-
OnyxUtils_1.default.multiGet(matchingKeys).then((values) => {
|
|
154
|
-
values.forEach((val, key) => {
|
|
155
|
-
OnyxUtils_1.default.sendDataToConnection(mapping, val, key, true);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
// If we are not subscribed to a collection key then there's only a single key to send an update for.
|
|
161
|
-
OnyxUtils_1.default.get(mapping.key).then((val) => OnyxUtils_1.default.sendDataToConnection(mapping, val, mapping.key, true));
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
// If we have a withOnyxInstance that means a React component has subscribed via the withOnyx() HOC and we need to
|
|
165
|
-
// group collection key member data into an object.
|
|
166
|
-
if ('withOnyxInstance' in mapping && mapping.withOnyxInstance) {
|
|
167
|
-
if (OnyxUtils_1.default.isCollectionKey(mapping.key)) {
|
|
168
|
-
OnyxUtils_1.default.getCollectionDataAndSendAsObject(matchingKeys, mapping);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
// If the subscriber is not using a collection key then we just send a single value back to the subscriber
|
|
172
|
-
OnyxUtils_1.default.get(mapping.key).then((val) => OnyxUtils_1.default.sendDataToConnection(mapping, val, mapping.key, true));
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
console.error('Warning: Onyx.connect() was found without a callback or withOnyxInstance');
|
|
176
|
-
});
|
|
177
|
-
// The connectionID is returned back to the caller so that it can be used to clean up the connection when it's no longer needed
|
|
178
|
-
// by calling Onyx.disconnect(connectionID).
|
|
179
|
-
return connectionID;
|
|
87
|
+
return OnyxConnectionManager_1.default.connect(connectOptions);
|
|
180
88
|
}
|
|
181
89
|
/**
|
|
182
|
-
*
|
|
90
|
+
* Disconnects and removes the listener from the Onyx key.
|
|
91
|
+
*
|
|
183
92
|
* @example
|
|
184
|
-
*
|
|
93
|
+
* ```ts
|
|
94
|
+
* const connection = Onyx.connect({
|
|
95
|
+
* key: ONYXKEYS.SESSION,
|
|
96
|
+
* callback: onSessionChange,
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* Onyx.disconnect(connection);
|
|
100
|
+
* ```
|
|
185
101
|
*
|
|
186
|
-
* @param
|
|
102
|
+
* @param connection Connection object returned by calling `Onyx.connect()`.
|
|
187
103
|
*/
|
|
188
|
-
function disconnect(
|
|
189
|
-
|
|
190
|
-
if (!callbackToStateMapping[connectionID]) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
// Remove this key from the eviction block list as we are no longer
|
|
194
|
-
// subscribing to it and it should be safe to delete again
|
|
195
|
-
if (keyToRemoveFromEvictionBlocklist) {
|
|
196
|
-
OnyxUtils_1.default.removeFromEvictionBlockList(keyToRemoveFromEvictionBlocklist, connectionID);
|
|
197
|
-
}
|
|
198
|
-
OnyxUtils_1.default.deleteKeyByConnections(lastConnectionID);
|
|
199
|
-
delete callbackToStateMapping[connectionID];
|
|
104
|
+
function disconnect(connection) {
|
|
105
|
+
OnyxConnectionManager_1.default.disconnect(connection);
|
|
200
106
|
}
|
|
201
107
|
/**
|
|
202
108
|
* Write a value to our store with the given key
|
|
@@ -510,8 +416,8 @@ function clear(keysToPreserve = []) {
|
|
|
510
416
|
const newValue = (_a = defaultKeyStates[key]) !== null && _a !== void 0 ? _a : null;
|
|
511
417
|
if (newValue !== oldValue) {
|
|
512
418
|
OnyxCache_1.default.set(key, newValue);
|
|
513
|
-
const collectionKey =
|
|
514
|
-
if (collectionKey) {
|
|
419
|
+
const collectionKey = OnyxUtils_1.default.getCollectionKey(key);
|
|
420
|
+
if (OnyxUtils_1.default.isCollectionKey(collectionKey)) {
|
|
515
421
|
if (!keyValuesToResetAsCollection[collectionKey]) {
|
|
516
422
|
keyValuesToResetAsCollection[collectionKey] = {};
|
|
517
423
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ConnectOptions } from './Onyx';
|
|
2
|
+
import type { OnyxKey } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Represents the connection object returned by `Onyx.connect()`.
|
|
5
|
+
*/
|
|
6
|
+
type Connection = {
|
|
7
|
+
/**
|
|
8
|
+
* The ID used to identify this particular connection.
|
|
9
|
+
*/
|
|
10
|
+
id: string;
|
|
11
|
+
/**
|
|
12
|
+
* The ID of the subscriber's callback that is associated to this connection.
|
|
13
|
+
*/
|
|
14
|
+
callbackID: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Manages Onyx connections of `Onyx.connect()`, `useOnyx()` and `withOnyx()` subscribers.
|
|
18
|
+
*/
|
|
19
|
+
declare class OnyxConnectionManager {
|
|
20
|
+
/**
|
|
21
|
+
* A map where the key is the connection ID generated inside `connect()` and the value is the metadata of that connection.
|
|
22
|
+
*/
|
|
23
|
+
private connectionsMap;
|
|
24
|
+
/**
|
|
25
|
+
* Stores the last generated callback ID which will be incremented when making a new connection.
|
|
26
|
+
*/
|
|
27
|
+
private lastCallbackID;
|
|
28
|
+
constructor();
|
|
29
|
+
/**
|
|
30
|
+
* Generates a connection ID based on the `connectOptions` object passed to the function.
|
|
31
|
+
*
|
|
32
|
+
* The properties used to generate the ID are handpicked for performance reasons and
|
|
33
|
+
* according to their purpose and effect they produce in the Onyx connection.
|
|
34
|
+
*/
|
|
35
|
+
private generateConnectionID;
|
|
36
|
+
/**
|
|
37
|
+
* Fires all the subscribers callbacks associated with that connection ID.
|
|
38
|
+
*/
|
|
39
|
+
private fireCallbacks;
|
|
40
|
+
/**
|
|
41
|
+
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
42
|
+
*
|
|
43
|
+
* @param connectOptions The options object that will define the behavior of the connection.
|
|
44
|
+
* @returns The connection object to use when calling `disconnect()`.
|
|
45
|
+
*/
|
|
46
|
+
connect<TKey extends OnyxKey>(connectOptions: ConnectOptions<TKey>): Connection;
|
|
47
|
+
/**
|
|
48
|
+
* Disconnects and removes the listener from the Onyx key.
|
|
49
|
+
*
|
|
50
|
+
* @param connection Connection object returned by calling `connect()`.
|
|
51
|
+
*/
|
|
52
|
+
disconnect(connection: Connection): void;
|
|
53
|
+
/**
|
|
54
|
+
* Disconnect all subscribers from Onyx.
|
|
55
|
+
*/
|
|
56
|
+
disconnectAll(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Adds the connection to the eviction block list. Connections added to this list can never be evicted.
|
|
59
|
+
* */
|
|
60
|
+
addToEvictionBlockList(connection: Connection): void;
|
|
61
|
+
/**
|
|
62
|
+
* Removes a connection previously added to this list
|
|
63
|
+
* which will enable it to be evicted again.
|
|
64
|
+
*/
|
|
65
|
+
removeFromEvictionBlockList(connection: Connection): void;
|
|
66
|
+
}
|
|
67
|
+
declare const connectionManager: OnyxConnectionManager;
|
|
68
|
+
export default connectionManager;
|
|
69
|
+
export type { Connection };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
const bindAll_1 = __importDefault(require("lodash/bindAll"));
|
|
30
|
+
const Logger = __importStar(require("./Logger"));
|
|
31
|
+
const OnyxUtils_1 = __importDefault(require("./OnyxUtils"));
|
|
32
|
+
const Str = __importStar(require("./Str"));
|
|
33
|
+
const utils_1 = __importDefault(require("./utils"));
|
|
34
|
+
/**
|
|
35
|
+
* Manages Onyx connections of `Onyx.connect()`, `useOnyx()` and `withOnyx()` subscribers.
|
|
36
|
+
*/
|
|
37
|
+
class OnyxConnectionManager {
|
|
38
|
+
constructor() {
|
|
39
|
+
this.connectionsMap = new Map();
|
|
40
|
+
this.lastCallbackID = 0;
|
|
41
|
+
// Binds all public methods to prevent problems with `this`.
|
|
42
|
+
(0, bindAll_1.default)(this, 'generateConnectionID', 'fireCallbacks', 'connect', 'disconnect', 'disconnectAll', 'addToEvictionBlockList', 'removeFromEvictionBlockList');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generates a connection ID based on the `connectOptions` object passed to the function.
|
|
46
|
+
*
|
|
47
|
+
* The properties used to generate the ID are handpicked for performance reasons and
|
|
48
|
+
* according to their purpose and effect they produce in the Onyx connection.
|
|
49
|
+
*/
|
|
50
|
+
generateConnectionID(connectOptions) {
|
|
51
|
+
var _a, _b;
|
|
52
|
+
let suffix = '';
|
|
53
|
+
// We will generate a unique ID in any of the following situations:
|
|
54
|
+
// - `connectOptions.reuseConnection` is `false`. That means the subscriber explicitly wants the connection to not be reused.
|
|
55
|
+
// - `connectOptions.initWithStoredValues` is `false`. This flag changes the subscription flow when set to `false`, so the connection can't be reused.
|
|
56
|
+
// - `withOnyxInstance` is defined inside `connectOptions`. That means the subscriber is a `withOnyx` HOC and therefore doesn't support connection reuse.
|
|
57
|
+
if (connectOptions.reuseConnection === false || connectOptions.initWithStoredValues === false || utils_1.default.hasWithOnyxInstance(connectOptions)) {
|
|
58
|
+
suffix += `,uniqueID=${Str.guid()}`;
|
|
59
|
+
}
|
|
60
|
+
return `onyxKey=${connectOptions.key},initWithStoredValues=${(_a = connectOptions.initWithStoredValues) !== null && _a !== void 0 ? _a : true},waitForCollectionCallback=${(_b = connectOptions.waitForCollectionCallback) !== null && _b !== void 0 ? _b : false}${suffix}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Fires all the subscribers callbacks associated with that connection ID.
|
|
64
|
+
*/
|
|
65
|
+
fireCallbacks(connectionID) {
|
|
66
|
+
const connection = this.connectionsMap.get(connectionID);
|
|
67
|
+
connection === null || connection === void 0 ? void 0 : connection.callbacks.forEach((callback) => {
|
|
68
|
+
callback(connection.cachedCallbackValue, connection.cachedCallbackKey);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Connects to an Onyx key given the options passed and listens to its changes.
|
|
73
|
+
*
|
|
74
|
+
* @param connectOptions The options object that will define the behavior of the connection.
|
|
75
|
+
* @returns The connection object to use when calling `disconnect()`.
|
|
76
|
+
*/
|
|
77
|
+
connect(connectOptions) {
|
|
78
|
+
const connectionID = this.generateConnectionID(connectOptions);
|
|
79
|
+
let connectionMetadata = this.connectionsMap.get(connectionID);
|
|
80
|
+
let subscriptionID;
|
|
81
|
+
const callbackID = String(this.lastCallbackID++);
|
|
82
|
+
// If there is no connection yet for that connection ID, we create a new one.
|
|
83
|
+
if (!connectionMetadata) {
|
|
84
|
+
let callback;
|
|
85
|
+
// If the subscriber is a `withOnyx` HOC we don't define `callback` as the HOC will use
|
|
86
|
+
// its own logic to handle the data.
|
|
87
|
+
if (!utils_1.default.hasWithOnyxInstance(connectOptions)) {
|
|
88
|
+
callback = (value, key) => {
|
|
89
|
+
const createdConnection = this.connectionsMap.get(connectionID);
|
|
90
|
+
if (createdConnection) {
|
|
91
|
+
// We signal that the first connection was made and now any new subscribers
|
|
92
|
+
// can fire their callbacks immediately with the cached value when connecting.
|
|
93
|
+
createdConnection.isConnectionMade = true;
|
|
94
|
+
createdConnection.cachedCallbackValue = value;
|
|
95
|
+
createdConnection.cachedCallbackKey = key;
|
|
96
|
+
this.fireCallbacks(connectionID);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
subscriptionID = OnyxUtils_1.default.subscribeToKey(Object.assign(Object.assign({}, connectOptions), { callback }));
|
|
101
|
+
connectionMetadata = {
|
|
102
|
+
subscriptionID,
|
|
103
|
+
onyxKey: connectOptions.key,
|
|
104
|
+
isConnectionMade: false,
|
|
105
|
+
callbacks: new Map(),
|
|
106
|
+
};
|
|
107
|
+
this.connectionsMap.set(connectionID, connectionMetadata);
|
|
108
|
+
}
|
|
109
|
+
// We add the subscriber's callback to the list of callbacks associated with this connection.
|
|
110
|
+
if (connectOptions.callback) {
|
|
111
|
+
connectionMetadata.callbacks.set(callbackID, connectOptions.callback);
|
|
112
|
+
}
|
|
113
|
+
// If the first connection is already made we want any new subscribers to receive the cached callback value immediately.
|
|
114
|
+
if (connectionMetadata.isConnectionMade) {
|
|
115
|
+
// Defer the callback execution to the next tick of the event loop.
|
|
116
|
+
// This ensures that the current execution flow completes and the result connection object is available when the callback fires.
|
|
117
|
+
Promise.resolve().then(() => {
|
|
118
|
+
var _a, _b;
|
|
119
|
+
(_b = (_a = connectOptions).callback) === null || _b === void 0 ? void 0 : _b.call(_a, connectionMetadata.cachedCallbackValue, connectionMetadata.cachedCallbackKey);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return { id: connectionID, callbackID };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Disconnects and removes the listener from the Onyx key.
|
|
126
|
+
*
|
|
127
|
+
* @param connection Connection object returned by calling `connect()`.
|
|
128
|
+
*/
|
|
129
|
+
disconnect(connection) {
|
|
130
|
+
if (!connection) {
|
|
131
|
+
Logger.logInfo(`[ConnectionManager] Attempted to disconnect passing an undefined connection object.`);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const connectionMetadata = this.connectionsMap.get(connection.id);
|
|
135
|
+
if (!connectionMetadata) {
|
|
136
|
+
Logger.logInfo(`[ConnectionManager] Attempted to disconnect but no connection was found.`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Removes the callback from the connection's callbacks map.
|
|
140
|
+
connectionMetadata.callbacks.delete(connection.callbackID);
|
|
141
|
+
// If the connection's callbacks map is empty we can safely unsubscribe from the Onyx key.
|
|
142
|
+
if (connectionMetadata.callbacks.size === 0) {
|
|
143
|
+
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
|
|
144
|
+
this.removeFromEvictionBlockList(connection);
|
|
145
|
+
this.connectionsMap.delete(connection.id);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Disconnect all subscribers from Onyx.
|
|
150
|
+
*/
|
|
151
|
+
disconnectAll() {
|
|
152
|
+
this.connectionsMap.forEach((connectionMetadata, connectionID) => {
|
|
153
|
+
OnyxUtils_1.default.unsubscribeFromKey(connectionMetadata.subscriptionID);
|
|
154
|
+
connectionMetadata.callbacks.forEach((_, callbackID) => {
|
|
155
|
+
this.removeFromEvictionBlockList({ id: connectionID, callbackID });
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
this.connectionsMap.clear();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Adds the connection to the eviction block list. Connections added to this list can never be evicted.
|
|
162
|
+
* */
|
|
163
|
+
addToEvictionBlockList(connection) {
|
|
164
|
+
var _a;
|
|
165
|
+
const connectionMetadata = this.connectionsMap.get(connection.id);
|
|
166
|
+
if (!connectionMetadata) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const evictionBlocklist = OnyxUtils_1.default.getEvictionBlocklist();
|
|
170
|
+
if (!evictionBlocklist[connectionMetadata.onyxKey]) {
|
|
171
|
+
evictionBlocklist[connectionMetadata.onyxKey] = [];
|
|
172
|
+
}
|
|
173
|
+
(_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.push(`${connection.id}_${connection.callbackID}`);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Removes a connection previously added to this list
|
|
177
|
+
* which will enable it to be evicted again.
|
|
178
|
+
*/
|
|
179
|
+
removeFromEvictionBlockList(connection) {
|
|
180
|
+
var _a, _b, _c;
|
|
181
|
+
const connectionMetadata = this.connectionsMap.get(connection.id);
|
|
182
|
+
if (!connectionMetadata) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const evictionBlocklist = OnyxUtils_1.default.getEvictionBlocklist();
|
|
186
|
+
evictionBlocklist[connectionMetadata.onyxKey] =
|
|
187
|
+
(_b = (_a = evictionBlocklist[connectionMetadata.onyxKey]) === null || _a === void 0 ? void 0 : _a.filter((evictionKey) => evictionKey !== `${connection.id}_${connection.callbackID}`)) !== null && _b !== void 0 ? _b : [];
|
|
188
|
+
// Remove the key if there are no more subscribers.
|
|
189
|
+
if (((_c = evictionBlocklist[connectionMetadata.onyxKey]) === null || _c === void 0 ? void 0 : _c.length) === 0) {
|
|
190
|
+
delete evictionBlocklist[connectionMetadata.onyxKey];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const connectionManager = new OnyxConnectionManager();
|
|
195
|
+
exports.default = connectionManager;
|