react-native-onyx 1.0.54 → 1.0.55
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 +51 -26
- 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 +51 -26
- package/lib/storage/__mocks__/index.js +1 -2
- package/package.json +1 -1
package/lib/Onyx.js
CHANGED
|
@@ -848,19 +848,33 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
|
|
|
848
848
|
*
|
|
849
849
|
* @param {String} key
|
|
850
850
|
* @param {*} value
|
|
851
|
+
* @param {Boolean} hasChanged
|
|
851
852
|
* @param {String} method
|
|
852
853
|
*/
|
|
853
|
-
function broadcastUpdate(key, value, method) {
|
|
854
|
+
function broadcastUpdate(key, value, hasChanged, method) {
|
|
854
855
|
// Logging properties only since values could be sensitive things we don't want to log
|
|
855
856
|
Logger.logInfo(`${method}() called for key: ${key}${_.isObject(value) ? ` properties: ${_.keys(value).join(',')}` : ''}`);
|
|
856
857
|
|
|
857
858
|
// Update subscribers if the cached value has changed, or when the subscriber specifically requires
|
|
858
859
|
// all updates regardless of value changes (indicated by initWithStoredValues set to false).
|
|
859
|
-
|
|
860
|
-
|
|
860
|
+
if (hasChanged) {
|
|
861
|
+
cache.set(key, value);
|
|
862
|
+
} else {
|
|
863
|
+
cache.addToAccessedKeys(key);
|
|
864
|
+
}
|
|
865
|
+
|
|
861
866
|
notifySubscribersOnNextTick(key, value, subscriber => hasChanged || subscriber.initWithStoredValues === false);
|
|
862
867
|
}
|
|
863
868
|
|
|
869
|
+
/**
|
|
870
|
+
* @private
|
|
871
|
+
* @param {String} key
|
|
872
|
+
* @returns {Boolean}
|
|
873
|
+
*/
|
|
874
|
+
function hasPendingMergeForKey(key) {
|
|
875
|
+
return Boolean(mergeQueue[key]);
|
|
876
|
+
}
|
|
877
|
+
|
|
864
878
|
/**
|
|
865
879
|
* Write a value to our store with the given key
|
|
866
880
|
*
|
|
@@ -874,8 +888,19 @@ function set(key, value) {
|
|
|
874
888
|
return remove(key);
|
|
875
889
|
}
|
|
876
890
|
|
|
891
|
+
if (hasPendingMergeForKey(key)) {
|
|
892
|
+
Logger.logAlert(`Onyx.set() called after Onyx.merge() for key: ${key}. It is recommended to use set() or merge() not both.`);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
const hasChanged = cache.hasValueChanged(key, value);
|
|
896
|
+
|
|
877
897
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
878
|
-
broadcastUpdate(key, value, 'set');
|
|
898
|
+
broadcastUpdate(key, value, hasChanged, 'set');
|
|
899
|
+
|
|
900
|
+
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
901
|
+
if (!hasChanged) {
|
|
902
|
+
return Promise.resolve();
|
|
903
|
+
}
|
|
879
904
|
|
|
880
905
|
return Storage.setItem(key, value)
|
|
881
906
|
.catch(error => evictStorageAndRetry(error, set, key, value));
|
|
@@ -918,11 +943,11 @@ function multiSet(data) {
|
|
|
918
943
|
* Merges an array of changes with an existing value
|
|
919
944
|
*
|
|
920
945
|
* @private
|
|
921
|
-
* @param {Array<*>} changes Array of changes that should be applied to the existing value
|
|
922
946
|
* @param {*} existingValue
|
|
947
|
+
* @param {Array<*>} changes Array of changes that should be applied to the existing value
|
|
923
948
|
* @returns {*}
|
|
924
949
|
*/
|
|
925
|
-
function applyMerge(
|
|
950
|
+
function applyMerge(existingValue, changes) {
|
|
926
951
|
const lastChange = _.last(changes);
|
|
927
952
|
|
|
928
953
|
if (_.isArray(existingValue) || _.isArray(lastChange)) {
|
|
@@ -931,14 +956,10 @@ function applyMerge(changes, existingValue) {
|
|
|
931
956
|
|
|
932
957
|
if (_.isObject(existingValue) || _.every(changes, _.isObject)) {
|
|
933
958
|
// Object values are merged one after the other
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
// Remove all first level keys that are explicitly set to null.
|
|
940
|
-
return _.omit(newData, value => _.isNull(value));
|
|
941
|
-
}, existingValue || {});
|
|
959
|
+
// lodash adds a small overhead so we don't use it here
|
|
960
|
+
// eslint-disable-next-line prefer-object-spread, rulesdir/prefer-underscore-method
|
|
961
|
+
return _.reduce(changes, (modifiedData, change) => fastMerge(modifiedData, change),
|
|
962
|
+
existingValue || {});
|
|
942
963
|
}
|
|
943
964
|
|
|
944
965
|
// If we have anything else we can't merge it so we'll
|
|
@@ -979,17 +1000,30 @@ function merge(key, changes) {
|
|
|
979
1000
|
.then((existingValue) => {
|
|
980
1001
|
try {
|
|
981
1002
|
// 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)
|
|
982
|
-
const batchedChanges = applyMerge(mergeQueue[key]);
|
|
1003
|
+
const batchedChanges = applyMerge(undefined, mergeQueue[key]);
|
|
983
1004
|
|
|
984
1005
|
// Clean up the write queue so we
|
|
985
1006
|
// don't apply these changes again
|
|
986
1007
|
delete mergeQueue[key];
|
|
987
1008
|
|
|
988
1009
|
// After that we merge the batched changes with the existing value
|
|
989
|
-
|
|
1010
|
+
let modifiedData = applyMerge(existingValue, [batchedChanges]);
|
|
1011
|
+
|
|
1012
|
+
// For objects, the key for null values needs to be removed from the object to ensure the value will get removed from storage completely.
|
|
1013
|
+
// On native, SQLite will remove top-level keys that are null. To be consistent, we remove them on web too.
|
|
1014
|
+
if (!_.isArray(modifiedData) && _.isObject(modifiedData)) {
|
|
1015
|
+
modifiedData = _.omit(modifiedData, value => _.isNull(value));
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
const hasChanged = cache.hasValueChanged(key, modifiedData);
|
|
990
1019
|
|
|
991
1020
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
992
|
-
broadcastUpdate(key, modifiedData, 'merge');
|
|
1021
|
+
broadcastUpdate(key, modifiedData, hasChanged, 'merge');
|
|
1022
|
+
|
|
1023
|
+
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
1024
|
+
if (!hasChanged) {
|
|
1025
|
+
return Promise.resolve();
|
|
1026
|
+
}
|
|
993
1027
|
|
|
994
1028
|
return Storage.mergeItem(key, batchedChanges, modifiedData);
|
|
995
1029
|
} catch (error) {
|
|
@@ -1000,15 +1034,6 @@ function merge(key, changes) {
|
|
|
1000
1034
|
});
|
|
1001
1035
|
}
|
|
1002
1036
|
|
|
1003
|
-
/**
|
|
1004
|
-
* @private
|
|
1005
|
-
* @param {String} key
|
|
1006
|
-
* @returns {Boolean}
|
|
1007
|
-
*/
|
|
1008
|
-
function hasPendingMergeForKey(key) {
|
|
1009
|
-
return Boolean(mergeQueue[key]);
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
1037
|
/**
|
|
1013
1038
|
* Merge user provided default key value pairs.
|
|
1014
1039
|
* @private
|
|
@@ -4,9 +4,8 @@ import fastMerge from '../../fastMerge';
|
|
|
4
4
|
let storageMapInternal = {};
|
|
5
5
|
|
|
6
6
|
const set = jest.fn((key, value) => {
|
|
7
|
-
// eslint-disable-next-line no-param-reassign
|
|
8
7
|
storageMapInternal[key] = value;
|
|
9
|
-
return Promise.resolve(
|
|
8
|
+
return Promise.resolve(value);
|
|
10
9
|
});
|
|
11
10
|
|
|
12
11
|
const localForageMock = {
|