react-native-onyx 1.0.55 → 1.0.56
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 +77 -8
- 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 +41 -0
- package/lib/withOnyx.js +35 -7
- package/package.json +1 -1
package/lib/Onyx.js
CHANGED
|
@@ -184,6 +184,46 @@ function isSafeEvictionKey(testKey) {
|
|
|
184
184
|
return _.some(evictionAllowList, key => isKeyMatch(key, testKey));
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Tries to get a value from the cache. If the value is not present in cache it will return the default value or undefined.
|
|
189
|
+
* If the requested key is a collection, it will return an object with all the collection members.
|
|
190
|
+
*
|
|
191
|
+
* @param {String} key
|
|
192
|
+
* @param {Object} mapping
|
|
193
|
+
* @returns {Mixed}
|
|
194
|
+
*/
|
|
195
|
+
function tryGetCachedValue(key, mapping = {}) {
|
|
196
|
+
let val = cache.getValue(key);
|
|
197
|
+
|
|
198
|
+
if (isCollectionKey(key)) {
|
|
199
|
+
const allKeys = cache.getAllKeys();
|
|
200
|
+
const matchingKeys = _.filter(allKeys, k => k.startsWith(key));
|
|
201
|
+
const values = _.reduce(matchingKeys, (finalObject, matchedKey) => {
|
|
202
|
+
const cachedValue = cache.getValue(matchedKey);
|
|
203
|
+
if (cachedValue) {
|
|
204
|
+
// This is permissible because we're in the process of constructing the final object in a reduce function.
|
|
205
|
+
// eslint-disable-next-line no-param-reassign
|
|
206
|
+
finalObject[matchedKey] = cachedValue;
|
|
207
|
+
}
|
|
208
|
+
return finalObject;
|
|
209
|
+
}, {});
|
|
210
|
+
if (_.isEmpty(values)) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
val = values;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (mapping.selector) {
|
|
217
|
+
const state = mapping.withOnyxInstance ? mapping.withOnyxInstance.state : undefined;
|
|
218
|
+
if (isCollectionKey(key)) {
|
|
219
|
+
return reduceCollectionWithSelector(val, mapping.selector, state);
|
|
220
|
+
}
|
|
221
|
+
return getSubsetOfData(val, mapping.selector, state);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return val;
|
|
225
|
+
}
|
|
226
|
+
|
|
187
227
|
/**
|
|
188
228
|
* Remove a key from the recently accessed key list.
|
|
189
229
|
*
|
|
@@ -1353,6 +1393,7 @@ const Onyx = {
|
|
|
1353
1393
|
isSafeEvictionKey,
|
|
1354
1394
|
METHOD,
|
|
1355
1395
|
setMemoryOnlyKeys,
|
|
1396
|
+
tryGetCachedValue,
|
|
1356
1397
|
};
|
|
1357
1398
|
|
|
1358
1399
|
/**
|
package/lib/withOnyx.js
CHANGED
|
@@ -37,13 +37,25 @@ export default function (mapOnyxToState) {
|
|
|
37
37
|
// disconnected. It is a key value store with the format {[mapping.key]: connectionID}.
|
|
38
38
|
this.activeConnectionIDs = {};
|
|
39
39
|
|
|
40
|
+
const cachedState = _.reduce(mapOnyxToState, (resultObj, mapping, propertyName) => {
|
|
41
|
+
const key = Str.result(mapping.key, props);
|
|
42
|
+
const value = Onyx.tryGetCachedValue(key, mapping);
|
|
43
|
+
|
|
44
|
+
if (value !== undefined) {
|
|
45
|
+
// eslint-disable-next-line no-param-reassign
|
|
46
|
+
resultObj[propertyName] = value;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return resultObj;
|
|
50
|
+
}, {});
|
|
51
|
+
|
|
52
|
+
// If we have all the data we need, then we can render the component immediately
|
|
53
|
+
cachedState.loading = _.size(cachedState) < requiredKeysForInit.length;
|
|
54
|
+
|
|
40
55
|
// Object holding the temporary initial state for the component while we load the various Onyx keys
|
|
41
|
-
this.tempState =
|
|
56
|
+
this.tempState = cachedState;
|
|
42
57
|
|
|
43
|
-
this.state =
|
|
44
|
-
// If there are no required keys for init then we can render the wrapped component immediately
|
|
45
|
-
loading: requiredKeysForInit.length > 0,
|
|
46
|
-
};
|
|
58
|
+
this.state = cachedState;
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
componentDidMount() {
|
|
@@ -60,7 +72,6 @@ export default function (mapOnyxToState) {
|
|
|
60
72
|
_.each(mapOnyxToState, (mapping, propertyName) => {
|
|
61
73
|
const previousKey = Str.result(mapping.key, prevProps);
|
|
62
74
|
const newKey = Str.result(mapping.key, this.props);
|
|
63
|
-
|
|
64
75
|
if (previousKey !== newKey) {
|
|
65
76
|
Onyx.disconnect(this.activeConnectionIDs[previousKey], previousKey);
|
|
66
77
|
delete this.activeConnectionIDs[previousKey];
|
|
@@ -88,6 +99,16 @@ export default function (mapOnyxToState) {
|
|
|
88
99
|
* @param {*} val
|
|
89
100
|
*/
|
|
90
101
|
setWithOnyxState(statePropertyName, val) {
|
|
102
|
+
// We might have loaded the values for the onyx keys/mappings already from the cache.
|
|
103
|
+
// In case we were able to load all the values upfront, the loading state will be false.
|
|
104
|
+
// However, Onyx.js will always call setWithOnyxState, as it doesn't know that this implementation
|
|
105
|
+
// already loaded the values from cache. Thus we have to check whether the value has changed
|
|
106
|
+
// before we set the state to prevent unnecessary renders.
|
|
107
|
+
const prevValue = this.state[statePropertyName];
|
|
108
|
+
if (!this.state.loading && prevValue === val) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
91
112
|
if (!this.state.loading) {
|
|
92
113
|
this.setState({[statePropertyName]: val});
|
|
93
114
|
return;
|
|
@@ -100,7 +121,14 @@ export default function (mapOnyxToState) {
|
|
|
100
121
|
return;
|
|
101
122
|
}
|
|
102
123
|
|
|
103
|
-
|
|
124
|
+
const stateUpdate = {...this.tempState, loading: false};
|
|
125
|
+
|
|
126
|
+
// The state is set here manually, instead of using setState because setState is an async operation, meaning it might execute on the next tick,
|
|
127
|
+
// or at a later point in the microtask queue. That can lead to a race condition where
|
|
128
|
+
// setWithOnyxState is called before the state is actually set. This results in unreliable behavior when checking the loading state and has been mainly observed on fabric.
|
|
129
|
+
this.state = stateUpdate;
|
|
130
|
+
|
|
131
|
+
this.setState(stateUpdate); // Trigger a render
|
|
104
132
|
delete this.tempState;
|
|
105
133
|
}
|
|
106
134
|
|