Back to Dashboard
Machine CodingINTERMEDIATE

Implement an Infinite Scroll component with real-time data fetching.

ReactHooksAPIPerformance

Live Interactive Demo

Loading Demo...

Implementation

typescript.tsx
import React, { useEffect, useState, useRef, useCallback } from 'react';

const InfiniteScroll = () => {
  const [photos, setPhotos] = __PH_44__([]);
  const [loading, setLoading] = __PH_45__(false);
  const [page, setPage] = __PH_46__(1);
  const [hasMore, setHasMore] = __PH_47__(true);
  const observer = __PH_48__();

  const lastElementRef = __PH_49__(node => {
    if (loading) return;
    if (observer.current) observer.current.disconnect();
    observer.current = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting && hasMore) {
        setPage(prev => prev + 1);
      }
    });
    if (node) observer.current.observe(node);
  }, [loading, hasMore]);

  __PH_50__(() => {
    if (photos.length >= 100) { setHasMore(false); return; }
    
    const fetchPhotos = async () => {
      setLoading(true);
      try {
        const res = await fetch(`https://picsum.photos/v2/list?page=${page}&limit=10`);
        const data = await res.json();
        setPhotos(prev => {
          const next = [...prev, ...data];
          if (next.length >= 100) setHasMore(false);
          return next.slice(0, 100);
        });
      } finally {
        setLoading(false);
      }
    };
    fetchPhotos();
  }, [page]);

  return (
    <div className='grid grid-cols-2 gap-4'>
      {photos.map((photo, i) => (
        <img 
          key={photo.id + i} 
          ref={i === photos.length - 1 ? lastElementRef : null}
          src={photo.download_url} 
          alt={photo.author} 
          className='rounded-lg w-full h-48 object-cover'
        />
      ))}
      {loading && <p>Loading...</p>}
      {!hasMore && <p className='col-span-2 text-center text-sm font-bold'>✨ Limit reached.</p>}
    </div>
  );
};

The Core Concept

Infinite scrolling allows users to load content continuously as they scroll down the page, improving UX for large datasets. Key concepts include:

1. **Intersection Observer API**: more performant than scroll event listeners as it doesn&apos;t run on every pixel scroll. 2. **Loading States**: managing &apos;isLoading&apos; to prevent duplicate requests. 3. **Page Management**: tracking the current page index for the API. 4. **Cleanup**: ensuring observers are disconnected when the component unmounts.

In this implementation, we use `picsum.photos` to fetch images and a ref-based &apos;trigger&apos; element at the bottom of the list.