DEV Community

Dharmesh
Dharmesh

Posted on

Infinite Scroll in React using IntersectionObserver

What is Infinite Scroll?

Infinite Scroll is a technique where additional data is automatically loaded as the user reaches the bottom of the page, creating a seamless browsing experience without requiring pagination or a "Load More" button.

Common use cases:

Social media feeds
E-commerce product listings
News feeds
Chat applications
Video streaming platforms
Why Use IntersectionObserver?

IntersectionObserver is a browser API that allows us to detect when an element enters or leaves the viewport.

Instead of continuously listening to scroll events, the browser efficiently notifies us when the observed element becomes visible.

Benefits
Better performance
Less memory consumption
Cleaner implementation
Browser-optimized visibility detection
Implementation Overview

The Infinite Scroll implementation consists of four main parts:

  1. State Management

We maintain:

data → stores fetched items
page → current page number
hasMore → determines if more data exists
loading → prevents duplicate requests
const [data, setData] = useState([]);
const [page, setPage] = useState(1);
const [hasMore, setHasMore] = useState(true);
const [loading, setLoading] = useState(false);

  1. Fetch Paginated Data

Whenever the page number changes, we fetch the next set of records.

useEffect(() => {
const handleData = async () => {
setLoading(true);

const res = await fetch(
  `https://rickandmortyapi.com/api/character?page=${page}`
);

const newItems = await res.json();

if (!newItems.info.next) {
  setHasMore(false);
}

setData((prev) => [
  ...prev,
  ...newItems.results,
]);

setLoading(false);
Enter fullscreen mode Exit fullscreen mode

};

handleData();
}, [page]);

  1. Create IntersectionObserver

The observer watches the loader element at the bottom of the page.

useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
const target = entries[0];

  if (
    target.isIntersecting &&
    hasMore &&
    !loading
  ) {
    setPage((prev) => prev + 1);
  }
}
Enter fullscreen mode Exit fullscreen mode

);

if (loaderRef.current) {
observer.observe(loaderRef.current);
}

return () => {
observer.disconnect();
};
}, [hasMore, loading]);

  1. Loader Element

This is the element being observed.

Loading more...

Once this element enters the viewport, the observer triggers the next API request.

How It Works
User Scrolls Down

Loader Enters Viewport

IntersectionObserver Fires

isIntersecting = true

Increment Page Number

API Request Sent

New Data Received

Append Data To Existing List

UI Re-renders

Process Repeats
Important Interview Points
Why not use scroll events?

Scroll events fire continuously while scrolling.

Scroll 1px
Scroll 2px
Scroll 3px
Scroll 4px
...

This can lead to performance issues.

IntersectionObserver is more efficient because the browser manages visibility detection internally.

Why use loading state?

To prevent multiple API calls while a request is already in progress.

if (
target.isIntersecting &&
hasMore &&
!loading
)

Without this condition, the observer may trigger multiple page increments before the previous request completes.

Why use hasMore?

To stop requesting data when the API has no more pages available.

if (!newItems.info.next) {
setHasMore(false);
}
Key Takeaways

✅ Clean implementation

✅ Better performance than scroll listeners

✅ Browser optimized

✅ Ideal for large datasets

✅ Frequently asked React interview question

Top comments (0)