react-native-onyx 1.0.81 → 1.0.83

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
@@ -25,18 +25,21 @@ If the requested key is a collection, it will return an object with all the coll
25
25
  <dt><a href="#disconnect">disconnect(connectionID, [keyToRemoveFromEvictionBlocklist])</a></dt>
26
26
  <dd><p>Remove the listener for a react component</p>
27
27
  </dd>
28
- <dt><a href="#notifySubscribersOnNextTick">notifySubscribersOnNextTick(key, value, [canUpdateSubscriber])</a></dt>
29
- <dd><p>This method mostly exists for historical reasons as this library was initially designed without a memory cache and one was added later.
30
- For this reason, Onyx works more similar to what you might expect from a native AsyncStorage with reads, writes, etc all becoming
31
- available async. Since we have code in our main applications that might expect things to work this way it&#39;s not safe to change this
32
- behavior just yet.</p>
28
+ <dt><a href="#maybeFlushBatchUpdates">maybeFlushBatchUpdates()</a> <code>Promise</code></dt>
29
+ <dd><p>We are batching together onyx updates. This helps with use cases where we schedule onyx updates after each other.
30
+ This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
31
+ update operations. Instead of calling the subscribers for each update operation, we batch them together which will
32
+ cause react to schedule the updates at once instead of after each other. This is mainly a performance optimization.</p>
33
33
  </dd>
34
- <dt><a href="#notifyCollectionSubscribersOnNextTick">notifyCollectionSubscribersOnNextTick(key, value)</a></dt>
34
+ <dt><a href="#scheduleSubscriberUpdate">scheduleSubscriberUpdate(key, value, [canUpdateSubscriber])</a> ⇒ <code>Promise</code></dt>
35
+ <dd><p>Schedules an update that will be appended to the macro task queue (so it doesn&#39;t update the subscribers immediately).</p>
36
+ </dd>
37
+ <dt><a href="#scheduleNotifyCollectionSubscribers">scheduleNotifyCollectionSubscribers(key, value)</a> ⇒ <code>Promise</code></dt>
35
38
  <dd><p>This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
36
39
  so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
37
40
  subscriber callbacks receive the data in a different format than they normally expect and it breaks code.</p>
38
41
  </dd>
39
- <dt><a href="#broadcastUpdate">broadcastUpdate(key, value, hasChanged, method)</a></dt>
42
+ <dt><a href="#broadcastUpdate">broadcastUpdate(key, value, hasChanged, method)</a> ⇒ <code>Promise</code></dt>
40
43
  <dd><p>Notifys subscribers and writes current value to cache</p>
41
44
  </dd>
42
45
  <dt><a href="#hasPendingMergeForKey">hasPendingMergeForKey(key)</a> ⇒ <code>Boolean</code></dt>
@@ -154,6 +157,7 @@ Subscribes a react component's state directly to a store key
154
157
  | [mapping.initWithStoredValues] | <code>Boolean</code> | If set to false, then no data will be prefilled into the component |
155
158
  | [mapping.waitForCollectionCallback] | <code>Boolean</code> | If set to true, it will return the entire collection to the callback as a single object |
156
159
  | [mapping.selector] | <code>function</code> | THIS PARAM IS ONLY USED WITH withOnyx(). If included, this will be used to subscribe to a subset of an Onyx key's data. 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). |
160
+ | [mapping.initialValue] | <code>String</code> \| <code>Number</code> \| <code>Boolean</code> \| <code>Object</code> | THIS PARAM IS ONLY USED WITH withOnyx(). If included, this will be passed to the component so that something can be rendered while data is being fetched from the DB. Note that it will not cause the component to have the loading prop set to true. | |
157
161
 
158
162
  **Example**
159
163
  ```js
@@ -178,13 +182,19 @@ Remove the listener for a react component
178
182
  ```js
179
183
  Onyx.disconnect(connectionID);
180
184
  ```
181
- <a name="notifySubscribersOnNextTick"></a>
185
+ <a name="maybeFlushBatchUpdates"></a>
186
+
187
+ ## maybeFlushBatchUpdates() ⇒ <code>Promise</code>
188
+ We are batching together onyx updates. This helps with use cases where we schedule onyx updates after each other.
189
+ This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
190
+ update operations. Instead of calling the subscribers for each update operation, we batch them together which will
191
+ cause react to schedule the updates at once instead of after each other. This is mainly a performance optimization.
192
+
193
+ **Kind**: global function
194
+ <a name="scheduleSubscriberUpdate"></a>
182
195
 
183
- ## notifySubscribersOnNextTick(key, value, [canUpdateSubscriber])
184
- This method mostly exists for historical reasons as this library was initially designed without a memory cache and one was added later.
185
- For this reason, Onyx works more similar to what you might expect from a native AsyncStorage with reads, writes, etc all becoming
186
- available async. Since we have code in our main applications that might expect things to work this way it's not safe to change this
187
- behavior just yet.
196
+ ## scheduleSubscriberUpdate(key, value, [canUpdateSubscriber]) ⇒ <code>Promise</code>
197
+ Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
188
198
 
189
199
  **Kind**: global function
190
200
 
@@ -196,11 +206,11 @@ behavior just yet.
196
206
 
197
207
  **Example**
198
208
  ```js
199
- notifySubscribersOnNextTick(key, value, subscriber => subscriber.initWithStoredValues === false)
209
+ scheduleSubscriberUpdate(key, value, subscriber => subscriber.initWithStoredValues === false)
200
210
  ```
201
- <a name="notifyCollectionSubscribersOnNextTick"></a>
211
+ <a name="scheduleNotifyCollectionSubscribers"></a>
202
212
 
203
- ## notifyCollectionSubscribersOnNextTick(key, value)
213
+ ## scheduleNotifyCollectionSubscribers(key, value) ⇒ <code>Promise</code>
204
214
  This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
205
215
  so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
206
216
  subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
@@ -214,7 +224,7 @@ subscriber callbacks receive the data in a different format than they normally e
214
224
 
215
225
  <a name="broadcastUpdate"></a>
216
226
 
217
- ## broadcastUpdate(key, value, hasChanged, method)
227
+ ## broadcastUpdate(key, value, hasChanged, method) ⇒ <code>Promise</code>
218
228
  Notifys subscribers and writes current value to cache
219
229
 
220
230
  **Kind**: global function
package/README.md CHANGED
@@ -135,7 +135,74 @@ export default withOnyx({
135
135
  })(App);
136
136
  ```
137
137
 
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.
138
+ While `Onyx.connect()` gives you more control on how your component reacts as data is fetched from disk, `withOnyx()` will delay the rendering of the wrapped component until all keys/entities have been fetched and passed to the component, this can be convenient for simple cases. This however, can really delay your application if many entities are connected to the same component, you can pass an `initialValue` to each key to allow Onyx to eagerly render your component with this value.
139
+
140
+ ```javascript
141
+ export default withOnyx({
142
+ session: {
143
+ key: ONYXKEYS.SESSION,
144
+ initialValue: {}
145
+ },
146
+ })(App);
147
+ ```
148
+
149
+ Additionally, if your component has many keys/entities when your component will mount but will receive many updates as data is fetched from DB and passed down to it, as every key that gets fetched will trigger a `setState` on the `withOnyx` HOC. This might cause re-renders on the initial mounting, preventing the component from mounting/rendering in reasonable time, making your app feel slow and even delaying animations. You can workaround this by passing an additional object with the `shouldDelayUpdates` property set to true. Onyx will then put all the updates in a queue until you decide when then should be applied, the component will receive a function `markReadyForHydration`. A good place to call this function is on the `onLayout` method, which gets triggered after your component has been rendered.
150
+
151
+ ```javascript
152
+ const App = ({session, markReadyForHydration}) => (
153
+ <View onLayout={() => markReadyForHydration()}>
154
+ {session.token ? <Text>Logged in</Text> : <Text>Logged out</Text> }
155
+ </View>
156
+ );
157
+
158
+ // Second argument to funciton is `shouldDelayUpdates`
159
+ export default withOnyx({
160
+ session: {
161
+ key: ONYXKEYS.SESSION,
162
+ initialValue: {}
163
+ },
164
+ }, true)(App);
165
+ ```
166
+
167
+ ### Dependent Onyx Keys and withOnyx()
168
+ Some components need to subscribe to multiple Onyx keys at once and sometimes, one key might rely on the data from another key. This is similar to a JOIN in SQL.
169
+
170
+ Example: To get the policy of a report, the `policy` key depends on the `report` key.
171
+
172
+ ```javascript
173
+ export default withOnyx({
174
+ report: {
175
+ key: ({reportID) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
176
+ },
177
+ policy: {
178
+ key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`,
179
+ },
180
+ })(App);
181
+ ```
182
+
183
+ Background info:
184
+ - The `key` value can be a function that returns the key that Onyx subscribes to
185
+ - The first argument to the `key` function is the `props` from the component
186
+
187
+ **Detailed explanation of how this is handled and rendered:**
188
+ 1. The component mounts with a `reportID={1234}` prop
189
+ 2. `withOnyx` evaluates the mapping
190
+ 3. `withOnyx` connects to the key `reports_1234` because of the prop passed to the component
191
+ 3. `withOnyx` connects to the key `policies_undefined` because `report` doesn't exist in the props yet, so the `policyID` defaults to `undefined`. * (see note below)
192
+ 4. Onyx reads the data and updates the state of `withOnyx` with:
193
+ - `report={{reportID: 1234, policyID: 1, ... the rest of the object ...}}`
194
+ - `policy={undefined}` (since there is no policy with ID `undefined`)
195
+ 5. There is still an `undefined` key in the mapping, so Onyx reads the data again
196
+ 6. This time `withOnyx` connects to the key `policies_1` because the `report` object exists in the component's state and it has a `policyID: 1`
197
+ 7. Onyx reads the data and updates the state of withOnyx with:
198
+ - `policy={{policyID: 1, ... the rest of the object ...}`
199
+ 8. Now all mappings have values that are defined (not undefined) and the component is rendered with all necessary data
200
+
201
+ * It is VERY important to NOT use empty string default values like `report.policyID || ''`. This results in the key returned to `withOnyx` as `policies_` which subscribes to the ENTIRE POLICY COLLECTION and is most assuredly not what you were intending. You can use a default of `0` (as long as you are reasonably sure that there is never a policyID=0). This allows Onyx to return `undefined` as the value of the policy key, which is handled by `withOnyx` appropriately.
202
+
203
+ DO NOT use more than one `withOnyx` component at a time. It adds overhead and prevents some optimizations like batched rendering from working to its full potential.
204
+
205
+ It's also beneficial to use a [selector](https://github.com/Expensify/react-native-onyx/blob/main/API.md#connectmapping--number) with the mapping in case you need to grab a single item in a collection (like a single report action).
139
206
 
140
207
  ## Collections
141
208