react-native-onyx 1.0.19 → 1.0.21
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/README.md +3 -0
- package/dist/web.development.js +137 -25
- package/dist/web.development.js.map +1 -1
- package/dist/web.min.js +1 -1
- package/dist/web.min.js.map +1 -1
- package/lib/Onyx.js +39 -11
- package/lib/metrics/PerformanceUtils.js +68 -0
- package/lib/withOnyx.js +3 -2
- package/package.json +1 -1
package/lib/Onyx.js
CHANGED
|
@@ -7,6 +7,7 @@ import * as Logger from './Logger';
|
|
|
7
7
|
import cache from './OnyxCache';
|
|
8
8
|
import createDeferredTask from './createDeferredTask';
|
|
9
9
|
import fastMerge from './fastMerge';
|
|
10
|
+
import * as PerformanceUtils from './metrics/PerformanceUtils';
|
|
10
11
|
|
|
11
12
|
// Keeps track of the last connectionID that was used so we can keep incrementing it
|
|
12
13
|
let lastConnectionID = 0;
|
|
@@ -261,7 +262,7 @@ function keysChanged(collectionKey, partialCollection) {
|
|
|
261
262
|
// 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
|
|
262
263
|
// 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().
|
|
263
264
|
const stateMappingKeys = _.keys(callbackToStateMapping);
|
|
264
|
-
for (let i = stateMappingKeys.length; i
|
|
265
|
+
for (let i = 0; i < stateMappingKeys.length; i++) {
|
|
265
266
|
const subscriber = callbackToStateMapping[stateMappingKeys[i]];
|
|
266
267
|
if (!subscriber) {
|
|
267
268
|
continue;
|
|
@@ -323,12 +324,13 @@ function keysChanged(collectionKey, partialCollection) {
|
|
|
323
324
|
if (isSubscribedToCollectionKey) {
|
|
324
325
|
subscriber.withOnyxInstance.setState((prevState) => {
|
|
325
326
|
const finalCollection = _.clone(prevState[subscriber.statePropertyName] || {});
|
|
326
|
-
|
|
327
327
|
const dataKeys = _.keys(partialCollection);
|
|
328
328
|
for (let j = 0; j < dataKeys.length; j++) {
|
|
329
329
|
const dataKey = dataKeys[j];
|
|
330
330
|
finalCollection[dataKey] = cachedCollection[dataKey];
|
|
331
331
|
}
|
|
332
|
+
|
|
333
|
+
PerformanceUtils.logSetStateCall(subscriber, prevState[subscriber.statePropertyName], finalCollection, 'keysChanged', collectionKey);
|
|
332
334
|
return {
|
|
333
335
|
[subscriber.statePropertyName]: finalCollection,
|
|
334
336
|
};
|
|
@@ -345,8 +347,17 @@ function keysChanged(collectionKey, partialCollection) {
|
|
|
345
347
|
continue;
|
|
346
348
|
}
|
|
347
349
|
|
|
348
|
-
subscriber.withOnyxInstance.setState({
|
|
349
|
-
|
|
350
|
+
subscriber.withOnyxInstance.setState((prevState) => {
|
|
351
|
+
const data = cachedCollection[subscriber.key];
|
|
352
|
+
const previousData = prevState[subscriber.statePropertyName];
|
|
353
|
+
if (data === previousData) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
PerformanceUtils.logSetStateCall(subscriber, previousData, data, 'keysChanged', collectionKey);
|
|
358
|
+
return {
|
|
359
|
+
[subscriber.statePropertyName]: data,
|
|
360
|
+
};
|
|
350
361
|
});
|
|
351
362
|
}
|
|
352
363
|
}
|
|
@@ -372,7 +383,7 @@ function keyChanged(key, data) {
|
|
|
372
383
|
// notify them if the key that changed is a collection member. Or if it is a regular key notify them when there is an exact match. Depending on whether the subscriber
|
|
373
384
|
// was connected via withOnyx we will call setState() directly on the withOnyx instance. If it is a regular connection we will pass the data to the provided callback.
|
|
374
385
|
const stateMappingKeys = _.keys(callbackToStateMapping);
|
|
375
|
-
for (let i = stateMappingKeys.length; i
|
|
386
|
+
for (let i = 0; i < stateMappingKeys.length; i++) {
|
|
376
387
|
const subscriber = callbackToStateMapping[stateMappingKeys[i]];
|
|
377
388
|
if (!subscriber || !isKeyMatch(subscriber.key, key)) {
|
|
378
389
|
continue;
|
|
@@ -397,19 +408,29 @@ function keyChanged(key, data) {
|
|
|
397
408
|
if (isCollectionKey(subscriber.key)) {
|
|
398
409
|
subscriber.withOnyxInstance.setState((prevState) => {
|
|
399
410
|
const collection = prevState[subscriber.statePropertyName] || {};
|
|
411
|
+
const newCollection = {
|
|
412
|
+
...collection,
|
|
413
|
+
[key]: data,
|
|
414
|
+
};
|
|
415
|
+
PerformanceUtils.logSetStateCall(subscriber, collection, newCollection, 'keyChanged', key);
|
|
400
416
|
return {
|
|
401
|
-
[subscriber.statePropertyName]:
|
|
402
|
-
...collection,
|
|
403
|
-
[key]: data,
|
|
404
|
-
},
|
|
417
|
+
[subscriber.statePropertyName]: newCollection,
|
|
405
418
|
};
|
|
406
419
|
});
|
|
407
420
|
continue;
|
|
408
421
|
}
|
|
409
422
|
|
|
410
423
|
// If we did not match on a collection key then we just set the new data to the state property
|
|
411
|
-
subscriber.withOnyxInstance.setState({
|
|
412
|
-
[subscriber.statePropertyName]
|
|
424
|
+
subscriber.withOnyxInstance.setState((prevState) => {
|
|
425
|
+
const previousData = prevState[subscriber.statePropertyName];
|
|
426
|
+
if (previousData === data) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
PerformanceUtils.logSetStateCall(subscriber, previousData, data, 'keyChanged', key);
|
|
431
|
+
return {
|
|
432
|
+
[subscriber.statePropertyName]: data,
|
|
433
|
+
};
|
|
413
434
|
});
|
|
414
435
|
continue;
|
|
415
436
|
}
|
|
@@ -439,6 +460,7 @@ function sendDataToConnection(config, val, matchedKey) {
|
|
|
439
460
|
}
|
|
440
461
|
|
|
441
462
|
if (config.withOnyxInstance) {
|
|
463
|
+
PerformanceUtils.logSetStateCall(config, null, val, 'sendDataToConnection');
|
|
442
464
|
config.withOnyxInstance.setWithOnyxState(config.statePropertyName, val);
|
|
443
465
|
} else if (_.isFunction(config.callback)) {
|
|
444
466
|
config.callback(val, matchedKey);
|
|
@@ -988,6 +1010,7 @@ function update(data) {
|
|
|
988
1010
|
* of Onyx running in different tabs/windows. Defaults to true for platforms that support local storage (web/desktop)
|
|
989
1011
|
* @param {String[]} [option.keysToDisableSyncEvents=[]] Contains keys for which
|
|
990
1012
|
* we want to disable sync event across tabs.
|
|
1013
|
+
* @param {Boolean} [options.debugSetState] Enables debugging setState() calls to connected components.
|
|
991
1014
|
* @example
|
|
992
1015
|
* Onyx.init({
|
|
993
1016
|
* keys: ONYXKEYS,
|
|
@@ -1004,6 +1027,7 @@ function init({
|
|
|
1004
1027
|
captureMetrics = false,
|
|
1005
1028
|
shouldSyncMultipleInstances = Boolean(global.localStorage),
|
|
1006
1029
|
keysToDisableSyncEvents = [],
|
|
1030
|
+
debugSetState = false,
|
|
1007
1031
|
} = {}) {
|
|
1008
1032
|
if (captureMetrics) {
|
|
1009
1033
|
// The code here is only bundled and applied when the captureMetrics is set
|
|
@@ -1011,6 +1035,10 @@ function init({
|
|
|
1011
1035
|
applyDecorators();
|
|
1012
1036
|
}
|
|
1013
1037
|
|
|
1038
|
+
if (debugSetState) {
|
|
1039
|
+
PerformanceUtils.setShouldDebugSetState(true);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1014
1042
|
if (maxCachedKeysCount > 0) {
|
|
1015
1043
|
cache.setRecentKeysLimit(maxCachedKeysCount);
|
|
1016
1044
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import lodashTransform from 'lodash/transform';
|
|
2
|
+
import _ from 'underscore';
|
|
3
|
+
|
|
4
|
+
let debugSetState = false;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Boolean} debug
|
|
8
|
+
*/
|
|
9
|
+
function setShouldDebugSetState(debug) {
|
|
10
|
+
debugSetState = debug;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Deep diff between two objects. Useful for figuring out what changed about an object from one render to the next so
|
|
15
|
+
* that state and props updates can be optimized.
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} object
|
|
18
|
+
* @param {Object} base
|
|
19
|
+
* @return {Object}
|
|
20
|
+
*/
|
|
21
|
+
function diffObject(object, base) {
|
|
22
|
+
function changes(obj, comparisonObject) {
|
|
23
|
+
return lodashTransform(obj, (result, value, key) => {
|
|
24
|
+
if (_.isEqual(value, comparisonObject[key])) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line no-param-reassign
|
|
29
|
+
result[key] = (_.isObject(value) && _.isObject(comparisonObject[key]))
|
|
30
|
+
? changes(value, comparisonObject[key])
|
|
31
|
+
: value;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return changes(object, base);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Provide insights into why a setState() call occurred by diffing the before and after values.
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} mapping
|
|
41
|
+
* @param {*} previousValue
|
|
42
|
+
* @param {*} newValue
|
|
43
|
+
* @param {String} caller
|
|
44
|
+
* @param {String} [keyThatChanged]
|
|
45
|
+
*/
|
|
46
|
+
function logSetStateCall(mapping, previousValue, newValue, caller, keyThatChanged) {
|
|
47
|
+
if (!debugSetState) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const logParams = {};
|
|
52
|
+
if (keyThatChanged) {
|
|
53
|
+
logParams.keyThatChanged = keyThatChanged;
|
|
54
|
+
}
|
|
55
|
+
if (_.isObject(newValue) && _.isObject(previousValue)) {
|
|
56
|
+
logParams.difference = diffObject(previousValue, newValue);
|
|
57
|
+
} else {
|
|
58
|
+
logParams.previousValue = previousValue;
|
|
59
|
+
logParams.newValue = newValue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.debug(`[Onyx-Debug] ${mapping.displayName} setState() called. Subscribed to key '${mapping.key}' (${caller})`, logParams);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export {
|
|
66
|
+
logSetStateCall,
|
|
67
|
+
setShouldDebugSetState,
|
|
68
|
+
};
|
package/lib/withOnyx.js
CHANGED
|
@@ -25,8 +25,8 @@ export default function (mapOnyxToState) {
|
|
|
25
25
|
.omit(config => config.initWithStoredValues === false)
|
|
26
26
|
.keys()
|
|
27
27
|
.value();
|
|
28
|
-
|
|
29
28
|
return (WrappedComponent) => {
|
|
29
|
+
const displayName = getDisplayName(WrappedComponent);
|
|
30
30
|
class withOnyx extends React.Component {
|
|
31
31
|
constructor(props) {
|
|
32
32
|
super(props);
|
|
@@ -152,6 +152,7 @@ export default function (mapOnyxToState) {
|
|
|
152
152
|
key,
|
|
153
153
|
statePropertyName,
|
|
154
154
|
withOnyxInstance: this,
|
|
155
|
+
displayName,
|
|
155
156
|
});
|
|
156
157
|
}
|
|
157
158
|
|
|
@@ -190,7 +191,7 @@ export default function (mapOnyxToState) {
|
|
|
190
191
|
withOnyx.defaultProps = {
|
|
191
192
|
forwardedRef: undefined,
|
|
192
193
|
};
|
|
193
|
-
withOnyx.displayName = `withOnyx(${
|
|
194
|
+
withOnyx.displayName = `withOnyx(${displayName})`;
|
|
194
195
|
return React.forwardRef((props, ref) => {
|
|
195
196
|
const Component = withOnyx;
|
|
196
197
|
// eslint-disable-next-line react/jsx-props-no-spreading
|