@@ -7,7 +7,6 @@ import * as Logger from './Logger';
77import type Onyx from './Onyx' ;
88import cache , { TASK } from './OnyxCache' ;
99import * as Str from './Str' ;
10- import unstable_batchedUpdates from './batch' ;
1110import Storage from './storage' ;
1211import type {
1312 CollectionKey ,
@@ -76,6 +75,9 @@ type OnyxMethod = ValueOf<typeof METHOD>;
7675let mergeQueue : Record < OnyxKey , Array < OnyxValue < OnyxKey > > > = { } ;
7776let mergeQueuePromise : Record < OnyxKey , Promise < void > > = { } ;
7877
78+ // Used to schedule subscriber update to the macro task queue
79+ let nextMacrotaskPromise : Promise < void > | null = null ;
80+
7981// Holds a mapping of all the React components that want their state subscribed to a store key
8082let callbackToStateMapping : Record < string , CallbackToStateMapping < OnyxKey > > = { } ;
8183
@@ -88,9 +90,6 @@ let onyxKeyToSubscriptionIDs = new Map();
8890// Optional user-provided key value states set when Onyx initializes or clears
8991let defaultKeyStates : Record < OnyxKey , OnyxValue < OnyxKey > > = { } ;
9092
91- let batchUpdatesPromise : Promise < void > | null = null ;
92- let batchUpdatesQueue : Array < ( ) => void > = [ ] ;
93-
9493// Used for comparison with a new update to avoid invoking the Onyx.connect callback with the same data.
9594let lastConnectionCallbackData = new Map < number , OnyxValue < OnyxKey > > ( ) ;
9695
@@ -212,43 +211,6 @@ function sendActionToDevTools(
212211 DevTools . registerAction ( utils . formatActionName ( method , key ) , value , key ? { [ key ] : mergedValue || value } : ( value as OnyxCollection < KeyValueMapping [ OnyxKey ] > ) ) ;
213212}
214213
215- /**
216- * We are batching together onyx updates. This helps with use cases where we schedule onyx updates after each other.
217- * This happens for example in the Onyx.update function, where we process API responses that might contain a lot of
218- * update operations. Instead of calling the subscribers for each update operation, we batch them together which will
219- * cause react to schedule the updates at once instead of after each other. This is mainly a performance optimization.
220- */
221- function maybeFlushBatchUpdates ( ) : Promise < void > {
222- if ( batchUpdatesPromise ) {
223- return batchUpdatesPromise ;
224- }
225-
226- batchUpdatesPromise = new Promise ( ( resolve ) => {
227- /* We use (setTimeout, 0) here which should be called once native module calls are flushed (usually at the end of the frame)
228- * We may investigate if (setTimeout, 1) (which in React Native is equal to requestAnimationFrame) works even better
229- * then the batch will be flushed on next frame.
230- */
231- setTimeout ( ( ) => {
232- const updatesCopy = batchUpdatesQueue ;
233- batchUpdatesQueue = [ ] ;
234- batchUpdatesPromise = null ;
235- unstable_batchedUpdates ( ( ) => {
236- for ( const applyUpdates of updatesCopy ) {
237- applyUpdates ( ) ;
238- }
239- } ) ;
240-
241- resolve ( ) ;
242- } , 0 ) ;
243- } ) ;
244- return batchUpdatesPromise ;
245- }
246-
247- function batchUpdates ( updates : ( ) => void ) : Promise < void > {
248- batchUpdatesQueue . push ( updates ) ;
249- return maybeFlushBatchUpdates ( ) ;
250- }
251-
252214/**
253215 * Takes a collection of items (eg. {testKey_1:{a:'a'}, testKey_2:{b:'b'}})
254216 * and runs it through a reducer function to return a subset of the data according to a selector.
@@ -634,7 +596,6 @@ function keysChanged<TKey extends CollectionKeyBase>(
634596 collectionKey : TKey ,
635597 partialCollection : OnyxCollection < KeyValueMapping [ TKey ] > ,
636598 partialPreviousCollection : OnyxCollection < KeyValueMapping [ TKey ] > | undefined ,
637- notifyConnectSubscribers = true ,
638599) : void {
639600 // We prepare the "cached collection" which is the entire collection + the new partial data that
640601 // was merged in via mergeCollection().
@@ -670,10 +631,6 @@ function keysChanged<TKey extends CollectionKeyBase>(
670631
671632 // Regular Onyx.connect() subscriber found.
672633 if ( typeof subscriber . callback === 'function' ) {
673- if ( ! notifyConnectSubscribers ) {
674- continue ;
675- }
676-
677634 // If they are subscribed to the collection key and using waitForCollectionCallback then we'll
678635 // send the whole cached collection.
679636 if ( isSubscribedToCollectionKey ) {
@@ -723,7 +680,6 @@ function keyChanged<TKey extends OnyxKey>(
723680 key : TKey ,
724681 value : OnyxValue < TKey > ,
725682 canUpdateSubscriber : ( subscriber ?: CallbackToStateMapping < OnyxKey > ) => boolean = ( ) => true ,
726- notifyConnectSubscribers = true ,
727683 isProcessingCollectionUpdate = false ,
728684) : void {
729685 // Add or remove this key from the recentlyAccessedKeys lists
@@ -765,9 +721,6 @@ function keyChanged<TKey extends OnyxKey>(
765721
766722 // Subscriber is a regular call to connect() and provided a callback
767723 if ( typeof subscriber . callback === 'function' ) {
768- if ( ! notifyConnectSubscribers ) {
769- continue ;
770- }
771724 if ( lastConnectionCallbackData . has ( subscriber . subscriptionID ) && lastConnectionCallbackData . get ( subscriber . subscriptionID ) === value ) {
772725 continue ;
773726 }
@@ -850,6 +803,23 @@ function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matchingKeys: Co
850803 } ) ;
851804}
852805
806+ /**
807+ * Delays promise resolution until the next macrotask to prevent race condition if the key subscription is in progress.
808+ *
809+ * @param callback The keyChanged/keysChanged callback
810+ * */
811+ function prepareSubscriberUpdate ( callback : ( ) => void ) : Promise < void > {
812+ if ( ! nextMacrotaskPromise ) {
813+ nextMacrotaskPromise = new Promise < void > ( ( resolve ) => {
814+ setTimeout ( ( ) => {
815+ nextMacrotaskPromise = null ;
816+ resolve ( ) ;
817+ } , 0 ) ;
818+ } ) ;
819+ }
820+ return Promise . all ( [ nextMacrotaskPromise , Promise . resolve ( ) . then ( callback ) ] ) . then ( ) ;
821+ }
822+
853823/**
854824 * Schedules an update that will be appended to the macro task queue (so it doesn't update the subscribers immediately).
855825 *
@@ -862,13 +832,11 @@ function scheduleSubscriberUpdate<TKey extends OnyxKey>(
862832 canUpdateSubscriber : ( subscriber ?: CallbackToStateMapping < OnyxKey > ) => boolean = ( ) => true ,
863833 isProcessingCollectionUpdate = false ,
864834) : Promise < void > {
865- const promise = Promise . resolve ( ) . then ( ( ) => keyChanged ( key , value , canUpdateSubscriber , true , isProcessingCollectionUpdate ) ) ;
866- batchUpdates ( ( ) => keyChanged ( key , value , canUpdateSubscriber , false , isProcessingCollectionUpdate ) ) ;
867- return Promise . all ( [ maybeFlushBatchUpdates ( ) , promise ] ) . then ( ( ) => undefined ) ;
835+ return prepareSubscriberUpdate ( ( ) => keyChanged ( key , value , canUpdateSubscriber , isProcessingCollectionUpdate ) ) ;
868836}
869837
870838/**
871- * This method is similar to notifySubscribersOnNextTick but it is built for working specifically with collections
839+ * This method is similar to scheduleSubscriberUpdate but it is built for working specifically with collections
872840 * so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
873841 * subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
874842 */
@@ -877,9 +845,7 @@ function scheduleNotifyCollectionSubscribers<TKey extends OnyxKey>(
877845 value : OnyxCollection < KeyValueMapping [ TKey ] > ,
878846 previousValue ?: OnyxCollection < KeyValueMapping [ TKey ] > ,
879847) : Promise < void > {
880- const promise = Promise . resolve ( ) . then ( ( ) => keysChanged ( key , value , previousValue , true ) ) ;
881- batchUpdates ( ( ) => keysChanged ( key , value , previousValue , false ) ) ;
882- return Promise . all ( [ maybeFlushBatchUpdates ( ) , promise ] ) . then ( ( ) => undefined ) ;
848+ return prepareSubscriberUpdate ( ( ) => keysChanged ( key , value , previousValue ) ) ;
883849}
884850
885851/**
@@ -1692,7 +1658,6 @@ function clearOnyxUtilsInternals() {
16921658 mergeQueuePromise = { } ;
16931659 callbackToStateMapping = { } ;
16941660 onyxKeyToSubscriptionIDs = new Map ( ) ;
1695- batchUpdatesQueue = [ ] ;
16961661 lastConnectionCallbackData = new Map ( ) ;
16971662}
16981663
@@ -1704,8 +1669,6 @@ const OnyxUtils = {
17041669 getDeferredInitTask,
17051670 initStoreValues,
17061671 sendActionToDevTools,
1707- maybeFlushBatchUpdates,
1708- batchUpdates,
17091672 get,
17101673 getAllKeys,
17111674 getCollectionKeys,
@@ -1763,10 +1726,6 @@ GlobalSettings.addGlobalSettingsChangeListener(({enablePerformanceMetrics}) => {
17631726
17641727 // @ts -expect-error Reassign
17651728 initStoreValues = decorateWithMetrics ( initStoreValues , 'OnyxUtils.initStoreValues' ) ;
1766- // @ts -expect-error Reassign
1767- maybeFlushBatchUpdates = decorateWithMetrics ( maybeFlushBatchUpdates , 'OnyxUtils.maybeFlushBatchUpdates' ) ;
1768- // @ts -expect-error Reassign
1769- batchUpdates = decorateWithMetrics ( batchUpdates , 'OnyxUtils.batchUpdates' ) ;
17701729 // @ts -expect-error Complex type signature
17711730 get = decorateWithMetrics ( get , 'OnyxUtils.get' ) ;
17721731 // @ts -expect-error Reassign
0 commit comments