react-native-onyx 1.0.56 → 1.0.58
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/web.development.js +176 -174
- 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 +40 -25
- package/package.json +1 -2
package/lib/Onyx.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/* eslint-disable no-continue */
|
|
2
2
|
import {deepEqual} from 'fast-equals';
|
|
3
|
-
import lodashGet from 'lodash/get';
|
|
4
3
|
import _ from 'underscore';
|
|
5
4
|
import * as Logger from './Logger';
|
|
6
5
|
import cache from './OnyxCache';
|
|
@@ -48,17 +47,13 @@ let defaultKeyStates = {};
|
|
|
48
47
|
const deferredInitTask = createDeferredTask();
|
|
49
48
|
|
|
50
49
|
/**
|
|
51
|
-
* Uses a selector
|
|
50
|
+
* Uses a selector function to return a simplified version of sourceData
|
|
52
51
|
* @param {Mixed} sourceData
|
|
53
|
-
* @param {
|
|
52
|
+
* @param {Function} selector Function that takes sourceData and returns a simplified version of it
|
|
54
53
|
* @param {Object} [withOnyxInstanceState]
|
|
55
|
-
* If it's a string, the selector is passed to lodashGet on the sourceData
|
|
56
|
-
* If it's a function, it is passed the sourceData and it should return the simplified data
|
|
57
54
|
* @returns {Mixed}
|
|
58
55
|
*/
|
|
59
|
-
const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => (
|
|
60
|
-
? selector(sourceData, withOnyxInstanceState)
|
|
61
|
-
: lodashGet(sourceData, selector));
|
|
56
|
+
const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => selector(sourceData, withOnyxInstanceState);
|
|
62
57
|
|
|
63
58
|
/**
|
|
64
59
|
* Takes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}})
|
|
@@ -706,11 +701,10 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
|
|
|
706
701
|
* @param {Boolean} [mapping.initWithStoredValues] If set to false, then no data will be prefilled into the
|
|
707
702
|
* component
|
|
708
703
|
* @param {Boolean} [mapping.waitForCollectionCallback] If set to true, it will return the entire collection to the callback as a single object
|
|
709
|
-
* @param {
|
|
710
|
-
*
|
|
711
|
-
*
|
|
712
|
-
*
|
|
713
|
-
* be expensive from a performance standpoint).
|
|
704
|
+
* @param {Function} [mapping.selector] THIS PARAM IS ONLY USED WITH withOnyx(). If included, this will be used to subscribe to a subset of an Onyx key's data.
|
|
705
|
+
* The sourceData and withOnyx state are passed to the selector and should return the simplified data. Using this setting on `withOnyx` can have very positive
|
|
706
|
+
* 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
|
|
707
|
+
* cause the component to re-render (and that can be expensive from a performance standpoint).
|
|
714
708
|
* @returns {Number} an ID to use when calling disconnect
|
|
715
709
|
*/
|
|
716
710
|
function connect(mapping) {
|
|
@@ -915,6 +909,24 @@ function hasPendingMergeForKey(key) {
|
|
|
915
909
|
return Boolean(mergeQueue[key]);
|
|
916
910
|
}
|
|
917
911
|
|
|
912
|
+
/**
|
|
913
|
+
* We generally want to remove top-level nullish values from objects written to disk and cache, because it decreases the amount of data stored in memory and on disk.
|
|
914
|
+
* On native, when merging an existing value with new changes, SQLite will use JSON_PATCH, which removes top-level nullish values.
|
|
915
|
+
* To be consistent with the behaviour for merge, we'll also want to remove nullish values for "set" operations.
|
|
916
|
+
* On web, IndexedDB will keep the top-level keys along with a null value and this uses up storage and memory.
|
|
917
|
+
* This method will ensure that keys for null values are removed before an object is written to disk and cache so that all platforms are storing the data in the same efficient way.
|
|
918
|
+
* @private
|
|
919
|
+
* @param {*} value
|
|
920
|
+
* @returns {*}
|
|
921
|
+
*/
|
|
922
|
+
function removeNullObjectValues(value) {
|
|
923
|
+
if (_.isArray(value) || !_.isObject(value)) {
|
|
924
|
+
return value;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
return _.omit(value, objectValue => _.isNull(objectValue));
|
|
928
|
+
}
|
|
929
|
+
|
|
918
930
|
/**
|
|
919
931
|
* Write a value to our store with the given key
|
|
920
932
|
*
|
|
@@ -932,18 +944,20 @@ function set(key, value) {
|
|
|
932
944
|
Logger.logAlert(`Onyx.set() called after Onyx.merge() for key: ${key}. It is recommended to use set() or merge() not both.`);
|
|
933
945
|
}
|
|
934
946
|
|
|
935
|
-
const
|
|
947
|
+
const valueWithNullRemoved = removeNullObjectValues(value);
|
|
948
|
+
|
|
949
|
+
const hasChanged = cache.hasValueChanged(key, valueWithNullRemoved);
|
|
936
950
|
|
|
937
951
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
938
|
-
broadcastUpdate(key,
|
|
952
|
+
broadcastUpdate(key, valueWithNullRemoved, hasChanged, 'set');
|
|
939
953
|
|
|
940
954
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
941
955
|
if (!hasChanged) {
|
|
942
956
|
return Promise.resolve();
|
|
943
957
|
}
|
|
944
958
|
|
|
945
|
-
return Storage.setItem(key,
|
|
946
|
-
.catch(error => evictStorageAndRetry(error, set, key,
|
|
959
|
+
return Storage.setItem(key, valueWithNullRemoved)
|
|
960
|
+
.catch(error => evictStorageAndRetry(error, set, key, valueWithNullRemoved));
|
|
947
961
|
}
|
|
948
962
|
|
|
949
963
|
/**
|
|
@@ -1040,19 +1054,21 @@ function merge(key, changes) {
|
|
|
1040
1054
|
.then((existingValue) => {
|
|
1041
1055
|
try {
|
|
1042
1056
|
// 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)
|
|
1043
|
-
|
|
1057
|
+
let batchedChanges = applyMerge(undefined, mergeQueue[key]);
|
|
1044
1058
|
|
|
1045
1059
|
// Clean up the write queue so we
|
|
1046
1060
|
// don't apply these changes again
|
|
1047
1061
|
delete mergeQueue[key];
|
|
1048
1062
|
|
|
1049
1063
|
// After that we merge the batched changes with the existing value
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
//
|
|
1053
|
-
//
|
|
1054
|
-
|
|
1055
|
-
|
|
1064
|
+
const modifiedData = removeNullObjectValues(applyMerge(existingValue, [batchedChanges]));
|
|
1065
|
+
|
|
1066
|
+
// On native platforms we use SQLite which utilises JSON_PATCH to merge changes.
|
|
1067
|
+
// JSON_PATCH generally removes top-level nullish values from the stored object.
|
|
1068
|
+
// When there is no existing value though, SQLite will just insert the changes as a new value and thus the top-level nullish values won't be removed.
|
|
1069
|
+
// Therefore we need to remove nullish values from the `batchedChanges` which are sent to the SQLite, if no existing value is present.
|
|
1070
|
+
if (!existingValue) {
|
|
1071
|
+
batchedChanges = removeNullObjectValues(batchedChanges);
|
|
1056
1072
|
}
|
|
1057
1073
|
|
|
1058
1074
|
const hasChanged = cache.hasValueChanged(key, modifiedData);
|
|
@@ -1382,7 +1398,6 @@ const Onyx = {
|
|
|
1382
1398
|
multiSet,
|
|
1383
1399
|
merge,
|
|
1384
1400
|
mergeCollection,
|
|
1385
|
-
hasPendingMergeForKey,
|
|
1386
1401
|
update,
|
|
1387
1402
|
clear,
|
|
1388
1403
|
getAllKeys,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-onyx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.58",
|
|
4
4
|
"author": "Expensify, Inc.",
|
|
5
5
|
"homepage": "https://expensify.com",
|
|
6
6
|
"description": "State management for React Native",
|
|
@@ -41,7 +41,6 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"ascii-table": "0.0.9",
|
|
43
43
|
"fast-equals": "^4.0.3",
|
|
44
|
-
"lodash": "^4.17.21",
|
|
45
44
|
"underscore": "^1.13.1"
|
|
46
45
|
},
|
|
47
46
|
"devDependencies": {
|