react-native-onyx 1.0.12 → 1.0.15

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/API.md CHANGED
@@ -76,6 +76,7 @@ Subscribes a react component's state directly to a store key
76
76
  | [mapping.withOnyxInstance] | <code>Object</code> | whose setState() method will be called with any changed data This is used by React components to connect to Onyx |
77
77
  | [mapping.callback] | <code>function</code> | a method that will be called with changed data This is used by any non-React code to connect to Onyx |
78
78
  | [mapping.initWithStoredValues] | <code>Boolean</code> | If set to false, then no data will be prefilled into the component |
79
+ | [mapping.waitForCollectionCallback] | <code>Boolean</code> | If set to true, it will return the entire collection to the callback as a single object |
79
80
 
80
81
  **Example**
81
82
  ```js
package/README.md CHANGED
@@ -86,11 +86,18 @@ Onyx.merge(ONYXKEYS.POLICY, {employeeList: ['Jack']}); // -> {employeeList: ['Ja
86
86
 
87
87
  ### Should I use `merge()` or `set()` or both?
88
88
 
89
- - Use `merge()` if we want to merge partial data into an existing `Array` or `Object`
90
- - Use `set()` if we are working with simple values (`String`, `Boolean`, etc), need to completely overwrite a complex property of an `Object`, or reset some data entirely.
89
+ - Use `merge()` when creating a new object
90
+ - Use `merge()` to merge partial data into an existing object
91
+ - Use `merge()` when storing simple values (`String`, `Boolean`, `Number`)
92
+ - Use `set()` when you need to delete an Onyx key completely from storage
93
+ - Use `set()` when you need to completely reset an object or array of data
91
94
 
92
95
  Consecutive calls to `Onyx.merge()` with the same key are batched in a stack and processed in the order that they were called. This helps avoid race conditions where one merge possibly finishes before another. However, it's important to note that calls to `Onyx.set()` are not batched together with calls to `Onyx.merge()`. For this reason, it is usually preferable to use one or the other, but not both. Onyx is a work-in-progress so always test code to make sure assumptions are correct!
93
96
 
97
+ ### Should I store things as an array or an object?
98
+
99
+ You should avoid arrays as much as possible. They do not work well with `merge()` because it can't update a single element in an array, it must always set the entire array each time. This forces you to use `set()` a lot, and as seen above, `merge()` is more performant and better to use in almost any situation. If you are working with an array of objects, then you should be using an Onyx collection because it's optimized for working with arrays of objects.
100
+
94
101
  ## Subscribing to data changes
95
102
 
96
103
  To set up a basic subscription for a given key use the `Onyx.connect()` method.
@@ -130,6 +137,80 @@ export default withOnyx({
130
137
 
131
138
  It is preferable to use the HOC over `Onyx.connect()` in React code as `withOnyx()` will delay the rendering of the wrapped component until all keys have been accessed and made available.
132
139
 
140
+ ## Collections
141
+
142
+ Collections allow keys with similar value types to be subscribed together by subscribing to the collection key. To define one, it must be included in the `ONYXKEYS.COLLECTION` object and it must be suffixed with an underscore. Member keys should use a unique identifier or index after the collection key prefix (e.g. `report_42`).
143
+
144
+ ```javascript
145
+ const ONYXKEYS = {
146
+ COLLECTION: {
147
+ REPORT: 'report_',
148
+ },
149
+ };
150
+ ```
151
+
152
+ ### Setting Collection Values
153
+
154
+ To save a new collection key we can either do:
155
+
156
+ ```js
157
+ Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`, report1);
158
+ ```
159
+
160
+ or we can set many at once with `mergeCollection()` (see below for guidance on best practices):
161
+
162
+ ```js
163
+ Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, {
164
+ [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1,
165
+ [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2,
166
+ [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3,
167
+ });
168
+ ```
169
+
170
+ ### Subscribing to Collections
171
+
172
+ There are several ways to subscribe to these keys:
173
+
174
+ ```javascript
175
+ withOnyx({
176
+ allReports: {key: ONYXKEYS.COLLECTION.REPORT},
177
+ })(MyComponent);
178
+ ```
179
+
180
+ This will add a prop to the component called `allReports` which is an object of collection member key/values. Changes to the individual member keys will modify the entire object and new props will be passed with each individual key update. The prop doesn't update on the initial rendering of the component until the entire collection has been read out of Onyx.
181
+
182
+ ```js
183
+ Onyx.connect({key: ONYXKEYS.COLLECTION.REPORT}, callback: (memberValue, memberKey) => {...}});
184
+ ```
185
+
186
+ This will fire the callback once per member key depending on how many collection member keys are currently stored. Changes to those keys after the initial callbacks fire will occur when each individual key is updated.
187
+
188
+ ```js
189
+ Onyx.connect({
190
+ key: ONYXKEYS.COLLECTION.REPORT,
191
+ waitForCollectionCallback: true,
192
+ callback: (allReports) => {...}},
193
+ });
194
+ ```
195
+
196
+ This final option forces `Onyx.connect()` to behave more like `withOnyx()` and only update the callback once with the entire collection initially and later with an updated version of the collection when individual keys update.
197
+
198
+ ### Performance Considerations When Using Collections
199
+
200
+ Be cautious when using collections as things can get out of hand if you have a subscriber hooked up to a collection key that has large numbers of individual keys. If this is the case, it is critical to use `mergeCollection()` over `merge()`.
201
+
202
+ Remember, `mergeCollection()` will notify a subscriber only *once* with the total collected values whereas each call to `merge()` would re-render a connected component *each time it is called*. Consider this example where `reports` is an array of reports that we want to index and save.
203
+
204
+ ```js
205
+ // Bad
206
+ _.each(reports, report => Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report)); // -> A component using withOnyx() will have it's state updated with each iteration
207
+
208
+ // Good
209
+ const values = {};
210
+ _.each(reports, report => values[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`] = report);
211
+ Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, values); // -> A component using withOnyx() will only have it's state updated once
212
+ ```
213
+
133
214
  ## Clean up
134
215
 
135
216
  To clear all data from `Onyx` we can use `Onyx.clear()`.
@@ -744,13 +744,26 @@ function keysChanged(collectionKey, collection) {
744
744
  return;
745
745
  }
746
746
 
747
+ /**
748
+ * e.g. Onyx.connect({key: ONYXKEYS.COLLECTION.REPORT, callback: ...});
749
+ */
747
750
  var isSubscribedToCollectionKey = isKeyMatch(subscriber.key, collectionKey) &&
748
751
  isCollectionKey(subscriber.key);
752
+
753
+ /**
754
+ * e.g. Onyx.connect({key: `${ONYXKEYS.COLLECTION.REPORT}{reportID}`, callback: ...});
755
+ */
749
756
  var isSubscribedToCollectionMemberKey = subscriber.key.startsWith(collectionKey);
750
757
 
751
758
  if (isSubscribedToCollectionKey) {
752
759
  if (_underscore.default.isFunction(subscriber.callback)) {
753
760
  var cachedCollection = getCachedCollection(collectionKey);
761
+
762
+ if (subscriber.waitForCollectionCallback) {
763
+ subscriber.callback(cachedCollection);
764
+ return;
765
+ }
766
+
754
767
  _underscore.default.each(collection, function (data, dataKey) {
755
768
  subscriber.callback(cachedCollection[dataKey], dataKey);
756
769
  });
@@ -813,7 +826,15 @@ function keyChanged(key, data) {
813
826
  }
814
827
 
815
828
  if (_underscore.default.isFunction(subscriber.callback)) {
829
+ if (subscriber.waitForCollectionCallback) {
830
+ var cachedCollection = getCachedCollection(subscriber.key);
831
+ cachedCollection[key] = data;
832
+ subscriber.callback(cachedCollection);
833
+ return;
834
+ }
835
+
816
836
  subscriber.callback(data, key);
837
+ return;
817
838
  }
818
839
 
819
840
  if (!subscriber.withOnyxInstance) {
@@ -882,7 +903,7 @@ function sendDataToConnection(config, val, key) {
882
903
  * This is used by any non-React code to connect to Onyx
883
904
  * @param {Boolean} [mapping.initWithStoredValues] If set to false, then no data will be prefilled into the
884
905
  * component
885
- * @param {Boolean} [mapping.waitForCollectionCallback] If set to true, it will trigger the callback once and return all data as a single object
906
+ * @param {Boolean} [mapping.waitForCollectionCallback] If set to true, it will return the entire collection to the callback as a single object
886
907
  * @returns {Number} an ID to use when calling disconnect
887
908
  */
888
909
  function connect(mapping) {