@@ -328,6 +328,7 @@ @implementation RCTScrollView {
328328 BOOL _allowNextScrollNoMatterWhat;
329329#if TARGET_OS_OSX // [macOS
330330 BOOL _notifyDidScroll;
331+ BOOL _disableScrollEvents;
331332 NSPoint _lastScrollPosition;
332333#endif // macOS]
333334 CGRect _lastClippedToRect;
@@ -570,8 +571,28 @@ - (void)setRemoveClippedSubviews:(__unused BOOL)removeClippedSubviews
570571
571572- (void )setFrame : (CGRect)frame
572573{
574+ #if !TARGET_OS_OSX // [macOS]
575+ [super setFrame: frame];
576+ #else // [macOS
577+ /* *
578+ * Setting the frame on the scroll view will randomly generate between 0 and 4 scroll events. These events happen
579+ * during the layout phase of the view which generates layout notifications that are sent through the bridge.
580+ * Because the bridge is heavily used, the scroll events are throttled and reach the JS thread with a random delay.
581+ * Because the scroll event stores the clip and content view size, delayed scroll events will submit stale layout
582+ * information that can break virtual list implemenations.
583+ * By disabling scroll events during the execution of the setFrame method and scheduling one notification on
584+ * the next run loop, we can mitigate the delayed scroll event by sending it at a time where the bridge is not busy.
585+ */
586+ _disableScrollEvents = YES ;
573587 [super setFrame: frame];
588+ _disableScrollEvents = NO ;
589+
590+ if (self.window != nil && !self.window .inLiveResize ) {
591+ [self performSelector: @selector (scrollViewDocumentViewBoundsDidChange: ) withObject: nil afterDelay: 0 ];
592+ }
593+ #endif // macOS]
574594 [self centerContentIfNeeded ];
595+
575596}
576597
577598- (void )insertReactSubview : (RCTUIView *)view atIndex : (NSInteger )atIndex // [macOS]
@@ -867,6 +888,10 @@ - (void)flashScrollIndicators
867888#if TARGET_OS_OSX // [macOS
868889- (void )scrollViewDocumentViewBoundsDidChange : (__unused NSNotification *)notification
869890{
891+ if (_disableScrollEvents) {
892+ return ;
893+ }
894+
870895 if (_scrollView.centerContent ) {
871896 // contentOffset setter dynamically centers content when _centerContent == YES
872897 [_scrollView setContentOffset: _scrollView.contentOffset];
0 commit comments