Introduction
Infinite scroll is a popular feature in modern web applications where content loads automatically as users scroll down the page. It improves user experience by removing pagination and making browsing smooth and continuous. You often see infinite scrolling in social media feeds, e-commerce websites, and blog platforms.
However, if not implemented correctly, infinite scroll can cause performance issues like slow rendering, high memory usage, and poor user experience. In this article, you will learn how to implement infinite scroll in React without performance issues using simple language, practical examples, and production-ready techniques.
What is Infinite Scroll?
Infinite scroll is a technique where new data is loaded automatically when the user reaches the bottom of the page.
Instead of clicking “Next Page,” users keep scrolling and content keeps loading.
Why Use Infinite Scroll?
Better user engagement
Smooth browsing experience
Reduces clicks and navigation
Ideal for large datasets
Challenges in Infinite Scroll
Too many API calls
Slow rendering
Memory leaks
Duplicate data loading
Poor SEO if not handled properly
Basic Approach
The core idea:
Detect when user reaches bottom
Fetch more data from API
Append new data to existing list
Step 1: Setup React Project
npx create-react-app infinite-scroll-app
cd infinite-scroll-app
npm start
Step 2: Create State and Fetch Data
import { useEffect, useState } from 'react';
function App() {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const fetchData = async () => {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}`);
const data = await res.json();
setItems(prev => [...prev, ...data]);
};
useEffect(() => {
fetchData();
}, [page]);
return (
<div>
{items.map(item => (
<p key={item.id}>{item.title}</p>
))}
</div>
);
}
export default App;
Step 3: Detect Scroll Position
useEffect(() => {
const handleScroll = () => {
if (window.innerHeight + document.documentElement.scrollTop >= document.documentElement.offsetHeight - 100) {
setPage(prev => prev + 1);
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
Problem with Basic Approach
This method can cause:
Too many re-renders
Frequent API calls
Performance lag
So we need optimization.
Step 4: Use Intersection Observer (Best Practice)
Instead of listening to scroll events, use Intersection Observer.
import { useRef, useCallback } from 'react';
const observer = useRef();
const lastItemRef = useCallback(node => {
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
setPage(prev => prev + 1);
}
});
if (node) observer.current.observe(node);
}, []);
Attach to last item:
{items.map((item, index) => {
if (index === items.length - 1) {
return <p ref={lastItemRef} key={item.id}>{item.title}</p>;
}
return <p key={item.id}>{item.title}</p>;
})}

Join the conversation! Your thoughts help the community grow.