@@ -422,9 +422,22 @@ function getCachedCollection<TKey extends CollectionKeyBase>(collectionKey: TKey
422
422
function keysChanged < TKey extends CollectionKeyBase > (
423
423
collectionKey : TKey ,
424
424
partialCollection : OnyxCollection < KeyValueMapping [ TKey ] > ,
425
+ previousPartialCollection : OnyxCollection < KeyValueMapping [ TKey ] > | undefined ,
425
426
notifyRegularSubscibers = true ,
426
427
notifyWithOnyxSubscibers = true ,
427
428
) : void {
429
+ const previousCollectionWithoutNestedNulls = previousPartialCollection === undefined ? { } : ( utils . removeNestedNullValues ( previousPartialCollection ) as Record < string , unknown > ) ;
430
+
431
+ // We prepare the "cached collection" which is the entire collection + the new partial data that
432
+ // was merged in via mergeCollection().
433
+ const cachedCollection = getCachedCollection ( collectionKey ) ;
434
+ const cachedCollectionWithoutNestedNulls = utils . removeNestedNullValues ( cachedCollection ) as Record < string , unknown > ;
435
+
436
+ // If the previous collection equals the new collection then we do not need to notify any subscribers.
437
+ if ( previousPartialCollection !== undefined && deepEqual ( cachedCollectionWithoutNestedNulls , previousCollectionWithoutNestedNulls ) ) {
438
+ return ;
439
+ }
440
+
428
441
// We are iterating over all subscribers similar to keyChanged(). However, we are looking for subscribers who are subscribing to either a collection key or
429
442
// individual collection key member for the collection that is being updated. It is important to note that the collection parameter cane be a PARTIAL collection
430
443
// and does not represent all of the combined keys and values for a collection key. It is just the "new" data that was merged in via mergeCollection().
@@ -450,11 +463,6 @@ function keysChanged<TKey extends CollectionKeyBase>(
450
463
*/
451
464
const isSubscribedToCollectionMemberKey = isCollectionMemberKey ( collectionKey , subscriber . key ) ;
452
465
453
- // We prepare the "cached collection" which is the entire collection + the new partial data that
454
- // was merged in via mergeCollection().
455
- const cachedCollection = getCachedCollection ( collectionKey ) ;
456
- const cachedCollectionWithoutNestedNulls = utils . removeNestedNullValues ( cachedCollection ) as Record < string , unknown > ;
457
-
458
466
// Regular Onyx.connect() subscriber found.
459
467
if ( typeof subscriber . callback === 'function' ) {
460
468
if ( ! notifyRegularSubscibers ) {
@@ -474,6 +482,11 @@ function keysChanged<TKey extends CollectionKeyBase>(
474
482
const dataKeys = Object . keys ( partialCollection ?? { } ) ;
475
483
for ( let j = 0 ; j < dataKeys . length ; j ++ ) {
476
484
const dataKey = dataKeys [ j ] ;
485
+
486
+ if ( deepEqual ( cachedCollectionWithoutNestedNulls [ dataKey ] , previousCollectionWithoutNestedNulls [ dataKey ] ) ) {
487
+ continue ;
488
+ }
489
+
477
490
subscriber . callback ( cachedCollectionWithoutNestedNulls [ dataKey ] , dataKey ) ;
478
491
}
479
492
continue ;
@@ -482,6 +495,10 @@ function keysChanged<TKey extends CollectionKeyBase>(
482
495
// And if the subscriber is specifically only tracking a particular collection member key then we will
483
496
// notify them with the cached data for that key only.
484
497
if ( isSubscribedToCollectionMemberKey ) {
498
+ if ( deepEqual ( cachedCollectionWithoutNestedNulls [ subscriber . key ] , previousCollectionWithoutNestedNulls [ subscriber . key ] ) ) {
499
+ continue ;
500
+ }
501
+
485
502
const subscriberCallback = subscriber . callback as DefaultConnectCallback < TKey > ;
486
503
subscriberCallback ( cachedCollectionWithoutNestedNulls [ subscriber . key ] , subscriber . key as TKey ) ;
487
504
continue ;
@@ -535,6 +552,10 @@ function keysChanged<TKey extends CollectionKeyBase>(
535
552
536
553
// If a React component is only interested in a single key then we can set the cached value directly to the state name.
537
554
if ( isSubscribedToCollectionMemberKey ) {
555
+ if ( deepEqual ( cachedCollectionWithoutNestedNulls [ subscriber . key ] , previousCollectionWithoutNestedNulls [ subscriber . key ] ) ) {
556
+ continue ;
557
+ }
558
+
538
559
// However, we only want to update this subscriber if the partial data contains a change.
539
560
// Otherwise, we would update them with a value they already have and trigger an unnecessary re-render.
540
561
const dataFromCollection = partialCollection ?. [ subscriber . key ] ;
@@ -592,14 +613,14 @@ function keysChanged<TKey extends CollectionKeyBase>(
592
613
*/
593
614
function keyChanged < TKey extends OnyxKey > (
594
615
key : TKey ,
595
- data : OnyxValue < TKey > ,
596
- prevData : OnyxValue < TKey > ,
616
+ value : OnyxValue < TKey > ,
617
+ previousValue : OnyxValue < TKey > ,
597
618
canUpdateSubscriber : ( subscriber ?: Mapping < OnyxKey > ) => boolean = ( ) => true ,
598
619
notifyRegularSubscibers = true ,
599
620
notifyWithOnyxSubscibers = true ,
600
621
) : void {
601
622
// Add or remove this key from the recentlyAccessedKeys lists
602
- if ( data !== null ) {
623
+ if ( value !== null ) {
603
624
addLastAccessedKey ( key ) ;
604
625
} else {
605
626
removeLastAccessedKey ( key ) ;
@@ -624,14 +645,14 @@ function keyChanged<TKey extends OnyxKey>(
624
645
const cachedCollection = getCachedCollection ( subscriber . key ) ;
625
646
const cachedCollectionWithoutNestedNulls = utils . removeNestedNullValues ( cachedCollection ) as Record < string , unknown > ;
626
647
627
- cachedCollectionWithoutNestedNulls [ key ] = data ;
648
+ cachedCollectionWithoutNestedNulls [ key ] = value ;
628
649
subscriber . callback ( cachedCollectionWithoutNestedNulls ) ;
629
650
continue ;
630
651
}
631
652
632
- const dataWithoutNestedNulls = utils . removeNestedNullValues ( data ) ;
653
+ const valueWithoutNestedNulls = utils . removeNestedNullValues ( value ) ;
633
654
const subscriberCallback = subscriber . callback as DefaultConnectCallback < TKey > ;
634
- subscriberCallback ( dataWithoutNestedNulls , key ) ;
655
+ subscriberCallback ( valueWithoutNestedNulls , key ) ;
635
656
continue ;
636
657
}
637
658
@@ -650,7 +671,7 @@ function keyChanged<TKey extends OnyxKey>(
650
671
subscriber . withOnyxInstance . setStateProxy ( ( prevState ) => {
651
672
const prevWithOnyxData = prevState [ subscriber . statePropertyName ] ;
652
673
const newWithOnyxData = {
653
- [ key ] : selector ( data , subscriber . withOnyxInstance . state ) ,
674
+ [ key ] : selector ( value , subscriber . withOnyxInstance . state ) ,
654
675
} ;
655
676
const prevDataWithNewData = {
656
677
...prevWithOnyxData ,
@@ -671,7 +692,7 @@ function keyChanged<TKey extends OnyxKey>(
671
692
const collection = prevState [ subscriber . statePropertyName ] || { } ;
672
693
const newCollection = {
673
694
...collection ,
674
- [ key ] : data ,
695
+ [ key ] : value ,
675
696
} ;
676
697
PerformanceUtils . logSetStateCall ( subscriber , collection , newCollection , 'keyChanged' , key ) ;
677
698
return {
@@ -685,10 +706,10 @@ function keyChanged<TKey extends OnyxKey>(
685
706
// returned by the selector and only if the selected data has changed.
686
707
if ( selector ) {
687
708
subscriber . withOnyxInstance . setStateProxy ( ( ) => {
688
- const previousValue = selector ( prevData , subscriber . withOnyxInstance . state ) ;
689
- const newValue = selector ( data , subscriber . withOnyxInstance . state ) ;
709
+ const prevValue = selector ( previousValue , subscriber . withOnyxInstance . state ) ;
710
+ const newValue = selector ( value , subscriber . withOnyxInstance . state ) ;
690
711
691
- if ( ! deepEqual ( previousValue , newValue ) ) {
712
+ if ( ! deepEqual ( prevValue , newValue ) ) {
692
713
return {
693
714
[ subscriber . statePropertyName ] : newValue ,
694
715
} ;
@@ -700,19 +721,19 @@ function keyChanged<TKey extends OnyxKey>(
700
721
701
722
// If we did not match on a collection key then we just set the new data to the state property
702
723
subscriber . withOnyxInstance . setStateProxy ( ( prevState ) => {
703
- const prevWithOnyxData = prevState [ subscriber . statePropertyName ] ;
724
+ const prevWithOnyxValue = prevState [ subscriber . statePropertyName ] ;
704
725
705
726
// Avoids triggering unnecessary re-renders when feeding empty objects
706
- if ( utils . isEmptyObject ( data ) && utils . isEmptyObject ( prevWithOnyxData ) ) {
727
+ if ( utils . isEmptyObject ( value ) && utils . isEmptyObject ( prevWithOnyxValue ) ) {
707
728
return null ;
708
729
}
709
- if ( prevWithOnyxData === data ) {
730
+ if ( prevWithOnyxValue === value ) {
710
731
return null ;
711
732
}
712
733
713
- PerformanceUtils . logSetStateCall ( subscriber , prevData , data , 'keyChanged' , key ) ;
734
+ PerformanceUtils . logSetStateCall ( subscriber , previousValue , value , 'keyChanged' , key ) ;
714
735
return {
715
- [ subscriber . statePropertyName ] : data ,
736
+ [ subscriber . statePropertyName ] : value ,
716
737
} ;
717
738
} ) ;
718
739
continue ;
@@ -866,11 +887,11 @@ function getCollectionDataAndSendAsObject<TKey extends OnyxKey>(matchingKeys: Co
866
887
function scheduleSubscriberUpdate < TKey extends OnyxKey > (
867
888
key : TKey ,
868
889
value : OnyxValue < TKey > ,
869
- prevValue : OnyxValue < TKey > ,
890
+ previousValue : OnyxValue < TKey > ,
870
891
canUpdateSubscriber : ( subscriber ?: Mapping < OnyxKey > ) => boolean = ( ) => true ,
871
892
) : Promise < void > {
872
- const promise = Promise . resolve ( ) . then ( ( ) => keyChanged ( key , value , prevValue , canUpdateSubscriber , true , false ) ) ;
873
- batchUpdates ( ( ) => keyChanged ( key , value , prevValue , canUpdateSubscriber , false , true ) ) ;
893
+ const promise = Promise . resolve ( ) . then ( ( ) => keyChanged ( key , value , previousValue , canUpdateSubscriber , true , false ) ) ;
894
+ batchUpdates ( ( ) => keyChanged ( key , value , previousValue , canUpdateSubscriber , false , true ) ) ;
874
895
return Promise . all ( [ maybeFlushBatchUpdates ( ) , promise ] ) . then ( ( ) => undefined ) ;
875
896
}
876
897
@@ -879,9 +900,13 @@ function scheduleSubscriberUpdate<TKey extends OnyxKey>(
879
900
* so that keysChanged() is triggered for the collection and not keyChanged(). If this was not done, then the
880
901
* subscriber callbacks receive the data in a different format than they normally expect and it breaks code.
881
902
*/
882
- function scheduleNotifyCollectionSubscribers < TKey extends OnyxKey > ( key : TKey , value : OnyxCollection < KeyValueMapping [ TKey ] > ) : Promise < void > {
883
- const promise = Promise . resolve ( ) . then ( ( ) => keysChanged ( key , value , true , false ) ) ;
884
- batchUpdates ( ( ) => keysChanged ( key , value , false , true ) ) ;
903
+ function scheduleNotifyCollectionSubscribers < TKey extends OnyxKey > (
904
+ key : TKey ,
905
+ value : OnyxCollection < KeyValueMapping [ TKey ] > ,
906
+ previousValue ?: OnyxCollection < KeyValueMapping [ TKey ] > ,
907
+ ) : Promise < void > {
908
+ const promise = Promise . resolve ( ) . then ( ( ) => keysChanged ( key , value , previousValue , true , false ) ) ;
909
+ batchUpdates ( ( ) => keysChanged ( key , value , previousValue , false , true ) ) ;
885
910
return Promise . all ( [ maybeFlushBatchUpdates ( ) , promise ] ) . then ( ( ) => undefined ) ;
886
911
}
887
912
0 commit comments