11import React , { useCallback , useEffect , useLayoutEffect , useMemo , useState } from 'react'
22import { InView } from 'react-intersection-observer'
3+ import { viewPortScrollingState } from './viewPort'
34
45interface IElementMeasurements {
56 width : string | number
@@ -11,12 +12,12 @@ interface IElementMeasurements {
1112 id : string | undefined
1213}
1314
14- const OPTIMIZE_PERIOD = 5000
1515const IDLE_CALLBACK_TIMEOUT = 100
1616
1717/**
1818 * This is a component that allows optimizing the amount of elements present in the DOM through replacing them
1919 * with placeholders when they aren't visible in the viewport.
20+ * Scroll timing issues, should be handled in viewPort.tsx where the scrolling state is tracked.
2021 *
2122 * @export
2223 * @param {(React.PropsWithChildren<{
@@ -83,14 +84,40 @@ export function VirtualElement({
8384 setInView ( visible )
8485 } , [ ] )
8586
87+ const isScrolling = ( ) : boolean => {
88+ // Don't do updates while scrolling:
89+ if ( viewPortScrollingState . isProgrammaticScrollInProgress ) {
90+ return true
91+ }
92+ // And wait if a programmatic scroll was done recently:
93+ const timeSinceLastProgrammaticScroll = Date . now ( ) - viewPortScrollingState . lastProgrammaticScrollTime
94+ if ( timeSinceLastProgrammaticScroll < 100 ) {
95+ return true
96+ }
97+ return false
98+ }
99+
86100 useEffect ( ( ) => {
87101 if ( inView === true ) {
88102 setIsShowingChildren ( true )
89103 return
90104 }
91105
92106 let idleCallback : number | undefined
93- const optimizeTimeout = window . setTimeout ( ( ) => {
107+ let optimizeTimeout : number | undefined
108+
109+ const scheduleOptimization = ( ) => {
110+ if ( optimizeTimeout ) {
111+ window . clearTimeout ( optimizeTimeout )
112+ }
113+ // Don't proceed if we're scrolling
114+ if ( isScrolling ( ) ) {
115+ // Reschedule for after the scroll should be complete
116+ const scrollDelay = 200
117+ window . clearTimeout ( optimizeTimeout )
118+ optimizeTimeout = window . setTimeout ( scheduleOptimization , scrollDelay )
119+ return
120+ }
94121 idleCallback = window . requestIdleCallback (
95122 ( ) => {
96123 if ( childRef ) {
@@ -102,14 +129,18 @@ export function VirtualElement({
102129 timeout : IDLE_CALLBACK_TIMEOUT ,
103130 }
104131 )
105- } , OPTIMIZE_PERIOD )
132+ }
133+
134+ // Schedule the optimization:
135+ scheduleOptimization ( )
106136
107137 return ( ) => {
108138 if ( idleCallback ) {
109139 window . cancelIdleCallback ( idleCallback )
110140 }
111-
112- window . clearTimeout ( optimizeTimeout )
141+ if ( optimizeTimeout ) {
142+ window . clearTimeout ( optimizeTimeout )
143+ }
113144 }
114145 } , [ childRef , inView ] )
115146
0 commit comments