8
Hooks

useInfiniteScroll

A hook that enables infinite scrolling by detecting when a sentinel element enters the viewport.

useInfiniteScroll

The useInfiniteScroll hook enables infinite scrolling functionality by detecting when a “sentinel” element (typically placed at the end of your list) becomes visible in the viewport. When this happens, a callback function is triggered that can be used to load more content.

Item 1
Item 2
Item 3
Item 4
Item 5

Installation

Install the useInfiniteScroll hook using:

npx axionjs-ui add hook use-infinite-scroll

File Structure

use-infinite-scroll.ts

Parameters

PropTypeDefault
callback
() => void
Required
options
IntersectionObserverInit
{ threshold: 0, rootMargin: '100px' }

Return Value

PropTypeDefault
sentinelRef
React.RefObject<T>
-

Examples

Advanced Infinite Scroll with Loading States

A more complete implementation with loading states, error handling, and end of list detection.

Horizontal Infinite Scroll

The useInfiniteScroll hook also works for horizontal scrolling:

function HorizontalInfiniteScroll() {
  const [images, setImages] = useState([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const [isLoading, setIsLoading] = useState(false);
  
  const loadMoreImages = useCallback(() => {
    if (isLoading || !hasMore) return;
    
    setIsLoading(true);
    
    // Fetch more images
    fetchImages(page)
      .then(newImages => {
        setImages(prev => [...prev, ...newImages]);
        setPage(prev => prev + 1);
        
        if (newImages.length < 20) {
          setHasMore(false);
        }
      })
      .finally(() => {
        setIsLoading(false);
      });
  }, [isLoading, page, hasMore]);
  
  // Use the hook with a custom root
  const containerRef = useRef(null);
  const sentinelRef = useInfiniteScroll(loadMoreImages, {
    root: containerRef.current,
    threshold: 0.1,
    rootMargin: "0px 100px 0px 0px" // Right margin for horizontal scrolling
  });
  
  return (
    <div 
      ref={containerRef}
      className="flex overflow-x-auto"
    >
      <div className="flex gap-4">
        {images.map(image => (
          <div key={image.id} className="min-w-[200px]">
            <img src={image.url} alt={image.alt} />
          </div>
        ))}
        
        {isLoading && <div className="min-w-[200px]">Loading...</div>}
        
        {hasMore && <div ref={sentinelRef} className="min-w-[1px]" />}
      </div>
    </div>
  );
}

Use Cases

  • Content Feeds: Social media feeds, news articles, blog posts
  • Product Listings: E-commerce product browsing, search results
  • Media Galleries: Image galleries, video playlists
  • Comments/Reviews: Loading additional comments or reviews
  • Long Documents: Breaking up long-form content into chunks
  • Chat Messages: Loading previous messages in a chat interface
  • Timeline Views: Loading more historical data as users scroll back in time

Accessibility

To ensure accessible infinite scroll implementations:

  • Add appropriate ARIA live regions for screen readers to announce when new content loads
  • Include a “Load more” button as an alternative to automatic loading
  • Maintain keyboard focus correctly when new content loads
  • Consider adding a “Back to top” button for long feeds
  • Set aria-busy="true" on the container during loading phases

Performance Considerations

  • Use Virtualization: For very large lists, consider pairing with virtualization (like react-virtualized or react-window)
  • Optimize Image Loading: Lazy load and optimize images within infinite scroll lists
  • Request Throttling: Ensure your callback throttles API requests appropriately
  • Cleanup: Always clean up observers when components unmount
  • DOM Size: Too many DOM elements can cause performance issues; consider removing old items when the list gets very long

Best Practices

  • Set appropriate rootMargin to trigger loading before the user reaches the end
  • Include visual loading indicators to provide feedback to users
  • Maintain scroll position when adding new items to the top of a list
  • Consider removing old items that are far off-screen to improve performance
  • Implement error handling and retry logic for failed data fetches
  • Track loading state to prevent duplicate requests

On this page