All questions

useInfiniteScroll

Premium

useInfiniteScroll

Infinite scroll loads the next page automatically as the user nears the bottom — no "Load more" button. The modern, jank-free way to detect "near the bottom" is a sentinel: an empty element placed at the end of the list, watched by an IntersectionObserver. When the sentinel scrolls into view, you fetch the next page. The catch is guarding against duplicate loads — the sentinel can fire repeatedly while a fetch is already in flight.

Implement useInfiniteScroll({ hasMore, loading, onLoadMore, rootMargin }). Return { sentinelRef }, a callback ref for the sentinel element. When it intersects and hasMore and not loading, call onLoadMore(). Use rootMargin to trigger early (before the sentinel is fully visible).

Signature

function useInfiniteScroll({ hasMore, loading, onLoadMore, rootMargin = '0px' }) {
  // returns { sentinelRef }
}

Examples

const { sentinelRef } = useInfiniteScroll({
  hasMore, loading, onLoadMore: fetchNextPage, rootMargin: '200px',
});
<>
  {items.map((it) => <Row key={it.id} {...it} />)}
  <div ref={sentinelRef} />   {/* fetches when this scrolls near view */}
</>

Notes

  • Sentinel + observer — attach the callback ref to a trailing element; observe it with IntersectionObserver.
  • Load condition — call onLoadMore() only when the sentinel isIntersecting and hasMore and !loading.
  • Duplicate guard — the loading flag stops repeated intersects from firing a second fetch mid-request.
  • Fresh values via a ref — the observer callback outlives renders; read the latest hasMore/loading/onLoadMore from a ref so it never acts on stale props. Disconnect on ref change / unmount; rootMargin lets you prefetch early.

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium