@@ -181,7 +181,10 @@ export const GameCarousel: React.FC = () => {
181181 const router = useRouter ( )
182182 const [ games , setGames ] = useState < GameData [ ] > ( SAMPLE_GAMES )
183183 const [ isPaused , setIsPaused ] = useState ( false )
184+ const [ isCarouselVisible , setIsCarouselVisible ] = useState ( false )
185+ const [ shouldLoadLiveGames , setShouldLoadLiveGames ] = useState ( false )
184186 const abortController = useRef < AbortController | null > ( null )
187+ const sectionRef = useRef < HTMLElement > ( null )
185188 const carouselRef = useRef < HTMLDivElement > ( null )
186189
187190 const handleGameStart = useCallback ( ( gameData : StreamedGame ) => {
@@ -300,7 +303,7 @@ export const GameCarousel: React.FC = () => {
300303 } , [ ] )
301304
302305 useEffect ( ( ) => {
303- if ( isPaused || ! carouselRef . current ) return
306+ if ( isPaused || ! isCarouselVisible || ! carouselRef . current ) return
304307
305308 const scroll = ( ) => {
306309 if ( carouselRef . current ) {
@@ -317,18 +320,74 @@ export const GameCarousel: React.FC = () => {
317320
318321 const interval = setInterval ( scroll , 20 )
319322 return ( ) => clearInterval ( interval )
320- } , [ isPaused ] )
323+ } , [ isPaused , isCarouselVisible ] )
321324
322325 useEffect ( ( ) => {
323- fetchNewGame ( )
324- fetchBroadcast ( )
326+ const section = sectionRef . current
327+
328+ if ( ! section || typeof IntersectionObserver === 'undefined' ) {
329+ setIsCarouselVisible ( true )
330+ setShouldLoadLiveGames ( true )
331+ return
332+ }
333+
334+ const observer = new IntersectionObserver (
335+ ( [ entry ] ) => {
336+ setIsCarouselVisible ( entry . isIntersecting )
337+
338+ if ( entry . isIntersecting ) {
339+ setShouldLoadLiveGames ( true )
340+ }
341+ } ,
342+ { rootMargin : '300px 0px' } ,
343+ )
344+
345+ observer . observe ( section )
346+
347+ return ( ) => observer . disconnect ( )
348+ } , [ ] )
349+
350+ useEffect ( ( ) => {
351+ if ( ! shouldLoadLiveGames ) return
352+
353+ const startLiveFeeds = ( ) => {
354+ fetchNewGame ( )
355+ fetchBroadcast ( )
356+ }
357+
358+ const windowWithIdleCallback = window as Window & {
359+ requestIdleCallback ?: (
360+ callback : IdleRequestCallback ,
361+ options ?: IdleRequestOptions ,
362+ ) => number
363+ cancelIdleCallback ?: ( handle : number ) => void
364+ }
365+
366+ if ( windowWithIdleCallback . requestIdleCallback ) {
367+ const idleHandle = windowWithIdleCallback . requestIdleCallback (
368+ startLiveFeeds ,
369+ {
370+ timeout : 2500 ,
371+ } ,
372+ )
373+
374+ return ( ) => {
375+ windowWithIdleCallback . cancelIdleCallback ?.( idleHandle )
376+ if ( abortController . current ) {
377+ abortController . current . abort ( )
378+ }
379+ }
380+ }
381+
382+ const timeoutId = window . setTimeout ( startLiveFeeds , 1000 )
325383
326384 return ( ) => {
385+ window . clearTimeout ( timeoutId )
327386 if ( abortController . current ) {
328387 abortController . current . abort ( )
329388 }
330389 }
331- } , [ fetchNewGame , fetchBroadcast ] )
390+ } , [ fetchNewGame , fetchBroadcast , shouldLoadLiveGames ] )
332391
333392 const handleGameClick = useCallback (
334393 ( game : GameData ) => {
@@ -340,7 +399,10 @@ export const GameCarousel: React.FC = () => {
340399 )
341400
342401 return (
343- < section className = "relative w-full overflow-y-visible py-6" >
402+ < section
403+ ref = { sectionRef }
404+ className = "relative w-full overflow-y-visible py-6"
405+ >
344406 < div className = "relative mb-10 w-full overflow-y-visible" >
345407 < motion . div
346408 ref = { carouselRef }
0 commit comments