@@ -382,6 +382,7 @@ @implementation RCTScrollView {
382
382
BOOL _allowNextScrollNoMatterWhat;
383
383
#if TARGET_OS_OSX // [macOS
384
384
BOOL _notifyDidScroll;
385
+ NSPoint _lastScrollPosition;
385
386
#endif // macOS]
386
387
CGRect _lastClippedToRect;
387
388
uint16_t _coalescingKey;
@@ -477,6 +478,7 @@ - (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDis
477
478
#else // [macOS
478
479
_scrollView.drawsBackground = NO ;
479
480
_scrollView.postsBoundsChangedNotifications = YES ;
481
+ _lastScrollPosition = NSZeroPoint ;
480
482
#endif // macOS]
481
483
482
484
#if !TARGET_OS_OSX // [macOS]
@@ -925,6 +927,22 @@ - (void)scrollViewDidScroll:(RCTCustomScrollView *)scrollView // [macOS]
925
927
{
926
928
NSTimeInterval now = CACurrentMediaTime ();
927
929
[self updateClippedSubviews ];
930
+
931
+ #if TARGET_OS_OSX // [macOS
932
+ /* *
933
+ * To check for effective scroll position changes, the comparison with lastScrollPosition should happen
934
+ * after updateClippedSubviews. updateClippedSubviews will update the display of the vertical/horizontal
935
+ * scrollers which can change the clipview bounds.
936
+ * This change also ensures that no onScroll events are sent when the React setFrame call is running,
937
+ * which could submit onScroll events while the content view was not setup yet.
938
+ */
939
+ BOOL didScroll = !NSEqualPoints (scrollView.contentView .bounds .origin , _lastScrollPosition);
940
+ if (!didScroll) {
941
+ return ;
942
+ }
943
+ _lastScrollPosition = scrollView.contentView .bounds .origin ;
944
+ #endif // macOS]
945
+
928
946
/* *
929
947
* TODO: this logic looks wrong, and it may be because it is. Currently, if _scrollEventThrottle
930
948
* is set to zero (the default), the "didScroll" event is only sent once per scroll, instead of repeatedly
0 commit comments