Back

Complete guide to infinite scrolling in React

Complete guide to infinite scrolling in React

Infinite scrolling is a UX pattern where new content loads as users scroll down a page. Common in social feeds, timelines, and news apps, it’s a smooth way to explore large datasets without using pagination buttons. In this guide, you’ll learn how to build infinite scroll in React using both a third-party library and a custom hook.

Key Takeaways

  • Learn 2 practical ways to implement infinite scrolling in React
  • Use a custom hook with IntersectionObserver or a third-party package
  • Handle loading states, pagination, and empty results

What is infinite scroll?

Infinite scroll loads new data as the user scrolls near the end of a list. It removes the need for pagination and creates a continuous browsing experience. You’ll see it in products like Instagram, Twitter, and Reddit.

Method 1: Using a package (react-infinite-scroll-component)

The easiest way to implement infinite scroll in React is with a well-tested package.

Step 1: Install

npm install react-infinite-scroll-component

Step 2: Basic usage example

import InfiniteScroll from 'react-infinite-scroll-component';

function Feed() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);

  const fetchMoreData = async () => {
    const res = await fetch(`/api/posts?page=${page}`);
    const newItems = await res.json();
    if (newItems.length === 0) setHasMore(false);
    else {
      setItems(prev => [...prev, ...newItems]);
      setPage(prev => prev + 1);
    }
  };

  return (
    <InfiniteScroll
      dataLength={items.length}
      next={fetchMoreData}
      hasMore={hasMore}
      loader={<h4>Loading...</h4>}
      endMessage={<p>No more results</p>}
    >
      {items.map(item => <div key={item.id}>{item.title}</div>)}
    </InfiniteScroll>
  );
}

Pros

  • Quick to set up
  • Built-in loading and end states

Cons

  • Less control over scroll logic
  • Adds package dependency

Method 2: Custom hook with IntersectionObserver

This method gives you full control and no extra dependencies.

Step 1: Create a hook

function useInfiniteScroll(callback, ref) {
  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) callback();
    });
    if (ref.current) observer.observe(ref.current);
    return () => observer.disconnect();
  }, [callback, ref]);
}

Step 2: Use in a component

function Feed() {
  const [items, setItems] = useState([]);
  const [page, setPage] = useState(1);
  const [hasMore, setHasMore] = useState(true);
  const sentinelRef = useRef(null);

  const loadMore = async () => {
    if (!hasMore) return;
    const res = await fetch(`/api/posts?page=${page}`);
    const newItems = await res.json();
    if (newItems.length === 0) setHasMore(false);
    else {
      setItems(prev => [...prev, ...newItems]);
      setPage(prev => prev + 1);
    }
  };

  useInfiniteScroll(loadMore, sentinelRef);

  return (
    <div>
      {items.map(item => <div key={item.id}>{item.title}</div>)}
      <div ref={sentinelRef} style={{ height: 1 }} />
    </div>
  );
}

Pros

  • Fully customizable
  • Works with any scroll logic or API

Cons

  • Requires more setup
  • IntersectionObserver not supported in IE11

Real-world patterns and tips

  • Debounce fetch calls to avoid overloading APIs
  • Show a spinner or skeleton loader for better UX
  • Add retry logic for network errors
  • Handle edge cases like zero results or empty pages
if (items.length === 0 && !hasMore) {
  return <p>No posts found.</p>;
}

Performance considerations

  • Use libraries like react-window for virtualization when rendering thousands of items
  • Memoize item components to prevent re-renders
  • Clean up observers properly to avoid memory leaks
useEffect(() => {
  const observer = new IntersectionObserver(...);
  return () => observer.disconnect();
}, []);

Conclusion

Infinite scroll is a common feature in modern UIs. Whether you prefer the simplicity of a package or the control of a custom hook, React makes both approaches accessible. Always consider performance and loading feedback when implementing infinite scroll.

FAQs

Using a library like `react-infinite-scroll-component` gives you a fast and convenient setup.

Set a `hasMore` flag to false when the API returns an empty array.

It can, if you're rendering too many items. Use virtualization tools like `react-window` to manage large lists.

Use `IntersectionObserver` to trigger data loading when a bottom `div` (sentinel) comes into view.

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers