diff --git a/API.md b/API.md index 233c2ebc0..82b7777f4 100644 --- a/API.md +++ b/API.md @@ -5,10 +5,10 @@ ## Functions
MixedMixedUses a selector string or function to return a simplified version of sourceData
ObjectObjectTakes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}}) and runs it through a reducer function to return a subset of the data according to a selector. The resulting collection will only contain items that are returned by the selector.
@@ -77,7 +77,7 @@ value will be saved to storage after the default value. -## getSubsetOfData(sourceData, selector) ⇒Mixed
+## getSubsetOfData(sourceData, selector, [withOnyxInstanceState]) ⇒ Mixed
Uses a selector string or function to return a simplified version of sourceData
**Kind**: global function
@@ -85,11 +85,12 @@ Uses a selector string or function to return a simplified version of sourceData
| Param | Type | Description |
| --- | --- | --- |
| sourceData | Mixed | |
-| selector | String \| function | If it's a string, the selector is passed to lodashGet on the sourceData If it's a function, it is passed the sourceData and it should return the simplified data |
+| selector | String \| function | |
+| [withOnyxInstanceState] | Object | If it's a string, the selector is passed to lodashGet on the sourceData If it's a function, it is passed the sourceData and it should return the simplified data |
-## reduceCollectionWithSelector(collection, selector) ⇒ Object
+## reduceCollectionWithSelector(collection, selector, [withOnyxInstanceState]) ⇒ Object
Takes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}})
and runs it through a reducer function to return a subset of the data according to a selector.
The resulting collection will only contain items that are returned by the selector.
@@ -100,6 +101,7 @@ The resulting collection will only contain items that are returned by the select
| --- | --- | --- |
| collection | Object | |
| selector | String \| function | (see method docs for getSubsetOfData() for full details) |
+| [withOnyxInstanceState] | Object | |
@@ -128,7 +130,7 @@ Subscribes a react component's state directly to a store key
| [mapping.callback] | function | a method that will be called with changed data This is used by any non-React code to connect to Onyx |
| [mapping.initWithStoredValues] | Boolean | If set to false, then no data will be prefilled into the component |
| [mapping.waitForCollectionCallback] | Boolean | If set to true, it will return the entire collection to the callback as a single object |
-| [mapping.selector] | String \| function | THIS PARAM IS ONLY USED WITH withOnyx(). If included, this will be used to subscribe to a subset of an Onyx key's data. If the selector is a string, the selector is passed to lodashGet on the sourceData. If the selector is a function, the sourceData is passed to the selector and should return the simplified data. Using this setting on `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). |
+| [mapping.selector] | String \| function | THIS PARAM IS ONLY USED WITH withOnyx(). If included, this will be used to subscribe to a subset of an Onyx key's data. If the selector is a string, the selector is passed to lodashGet on the sourceData. If the selector is a function, 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 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). |
**Example**
```js
diff --git a/lib/Onyx.js b/lib/Onyx.js
index 43427aefa..8244dacbf 100644
--- a/lib/Onyx.js
+++ b/lib/Onyx.js
@@ -48,12 +48,13 @@ const deferredInitTask = createDeferredTask();
* Uses a selector string or function to return a simplified version of sourceData
* @param {Mixed} sourceData
* @param {String|Function} selector
+ * @param {Object} [withOnyxInstanceState]
* If it's a string, the selector is passed to lodashGet on the sourceData
* If it's a function, it is passed the sourceData and it should return the simplified data
* @returns {Mixed}
*/
-const getSubsetOfData = (sourceData, selector) => (_.isFunction(selector)
- ? selector(sourceData)
+const getSubsetOfData = (sourceData, selector, withOnyxInstanceState) => (_.isFunction(selector)
+ ? selector(sourceData, withOnyxInstanceState)
: lodashGet(sourceData, selector));
/**
@@ -62,11 +63,12 @@ const getSubsetOfData = (sourceData, selector) => (_.isFunction(selector)
* The resulting collection will only contain items that are returned by the selector.
* @param {Object} collection
* @param {String|Function} selector (see method docs for getSubsetOfData() for full details)
+ * @param {Object} [withOnyxInstanceState]
* @returns {Object}
*/
-const reduceCollectionWithSelector = (collection, selector) => _.reduce(collection, (finalCollection, item, key) => {
+const reduceCollectionWithSelector = (collection, selector, withOnyxInstanceState) => _.reduce(collection, (finalCollection, item, key) => {
// eslint-disable-next-line no-param-reassign
- finalCollection[key] = getSubsetOfData(item, selector);
+ finalCollection[key] = getSubsetOfData(item, selector, withOnyxInstanceState);
return finalCollection;
}, {});
@@ -362,8 +364,8 @@ function keysChanged(collectionKey, partialCollection) {
// returned by the selector.
if (subscriber.selector) {
subscriber.withOnyxInstance.setState((prevState) => {
- const previousData = reduceCollectionWithSelector(prevState[subscriber.statePropertyName], subscriber.selector);
- const newData = reduceCollectionWithSelector(cachedCollection, subscriber.selector);
+ const previousData = reduceCollectionWithSelector(prevState[subscriber.statePropertyName], subscriber.selector, subscriber.withOnyxInstance.state);
+ const newData = reduceCollectionWithSelector(cachedCollection, subscriber.selector, subscriber.withOnyxInstance.state);
if (!deepEqual(previousData, newData)) {
return {
@@ -406,7 +408,7 @@ function keysChanged(collectionKey, partialCollection) {
if (subscriber.selector) {
subscriber.withOnyxInstance.setState((prevState) => {
const prevData = prevState[subscriber.statePropertyName];
- const newData = getSubsetOfData(cachedCollection[subscriber.key], subscriber.selector);
+ const newData = getSubsetOfData(cachedCollection[subscriber.key], subscriber.selector, subscriber.withOnyxInstance.state);
if (!deepEqual(prevData, newData)) {
PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keysChanged', collectionKey);
return {
@@ -488,11 +490,11 @@ function keyChanged(key, data, canUpdateSubscriber) {
subscriber.withOnyxInstance.setState((prevState) => {
const prevData = prevState[subscriber.statePropertyName];
const newData = {
- [key]: getSubsetOfData(data, subscriber.selector),
+ [key]: getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state),
};
const prevDataWithNewData = {
...prevData,
- [key]: getSubsetOfData(data, subscriber.selector),
+ [key]: getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state),
};
if (!deepEqual(prevData, prevDataWithNewData)) {
PerformanceUtils.logSetStateCall(subscriber, prevData, newData, 'keyChanged', key);
@@ -523,8 +525,8 @@ function keyChanged(key, data, canUpdateSubscriber) {
// returned by the selector and only if the selected data has changed.
if (subscriber.selector) {
subscriber.withOnyxInstance.setState((prevState) => {
- const previousValue = getSubsetOfData(prevState[subscriber.statePropertyName], subscriber.selector);
- const newValue = getSubsetOfData(data, subscriber.selector);
+ const previousValue = getSubsetOfData(prevState[subscriber.statePropertyName], subscriber.selector, subscriber.withOnyxInstance.state);
+ const newValue = getSubsetOfData(data, subscriber.selector, subscriber.withOnyxInstance.state);
if (!deepEqual(previousValue, newValue)) {
return {
[subscriber.statePropertyName]: newValue,
@@ -582,9 +584,9 @@ function sendDataToConnection(mapping, val, matchedKey) {
// returned by the selector.
if (mapping.selector) {
if (isCollectionKey(mapping.key)) {
- newData = reduceCollectionWithSelector(val, mapping.selector);
+ newData = reduceCollectionWithSelector(val, mapping.selector, mapping.withOnyxInstance.state);
} else {
- newData = getSubsetOfData(val, mapping.selector);
+ newData = getSubsetOfData(val, mapping.selector, mapping.withOnyxInstance.state);
}
}
@@ -662,9 +664,10 @@ function getCollectionDataAndSendAsObject(matchingKeys, mapping) {
* component
* @param {Boolean} [mapping.waitForCollectionCallback] If set to true, it will return the entire collection to the callback as a single object
* @param {String|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.
- * If the selector is a string, the selector is passed to lodashGet on the sourceData. If the selector is a function, the sourceData is passed to the selector and should return the
- * simplified data. Using this setting on `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).
+ * If the selector is a string, the selector is passed to lodashGet on the sourceData. If the selector is a function, 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 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).
* @returns {Number} an ID to use when calling disconnect
*/
function connect(mapping) {
diff --git a/tests/unit/subscribeToPropertiesTest.js b/tests/unit/subscribeToPropertiesTest.js
index 3dc4c3a51..3af41a544 100644
--- a/tests/unit/subscribeToPropertiesTest.js
+++ b/tests/unit/subscribeToPropertiesTest.js
@@ -181,13 +181,18 @@ describe('Only the specific property changes when using withOnyx() and ', () =>
});
it('connecting to a collection with a selector function', () => {
+ const mockedSelector = jest.fn(obj => obj && obj.a);
const TestComponentWithOnyx = withOnyx({
collectionWithPropertyA: {
key: ONYX_KEYS.COLLECTION.TEST_KEY,
- selector: obj => obj && obj.a,
+ selector: mockedSelector,
},
})(ViewWithObject);
- return runAllAssertionsForCollection(TestComponentWithOnyx);
+ return runAllAssertionsForCollection(TestComponentWithOnyx)
+ .then(() => {
+ // Check to make sure that the selector was called with the props that are passed to the rendered component
+ expect(mockedSelector).toHaveBeenNthCalledWith(5, {a: 'two', b: 'two'}, {loading: false, collectionWithPropertyA: {test_1: 'one', test_2: undefined}});
+ });
});
/**