Building an Infinite Scroll Component in React

Building an Infinite Scroll Component in React
Suraj Vishwakarma
Updated
Originally Published
Navigation Map
Introduction
Infinite scrolling is a common feature in modern applications, especially social media platforms that encourage continuous engagement. While excessive scrolling isn't always beneficial, building an infinite scroll component from scratch is a great learning experience for developers.
In this guide, you'll learn how to implement an optimized infinite scroll in React. This tutorial covers:
- Setting up the environment
- Building the infinite scroll component
- Styling with CSS
- Optimizing scroll performance
Let's get started!
Environment Setup
We will use Create React App (CRA) to set up the project. Run the following command:
npx create-react-app infinite-scroll
Alternatively, you can use Vite or Next.js with minimal modifications.
Note: Ensure Node.js is installed before running the command. Also, clean up the CRA boilerplate code.
Next, install Axios to fetch data from an API:
npm install axios
Now, let's build the component.
App Component
We'll fetch popular movie data from TMDB API. Obtain a free API key from their website.
App.js
import "./App.css";
import { useState, useEffect } from "react";
import axios from "axios";
import { MovieCard } from "./MovieCard";
function App() {
const [page, setPage] = useState(1);
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const fetchMovie = async () => {
const URL = `https://api.themoviedb.org/3/movie/popular?language=en-US&page=${page}`;
const response = await axios.get(URL, {
headers: {
Authorization: "Bearer YOUR_API_KEY",
Accept: "application/json",
},
});
setData((prevData) => [...prevData, ...response.data.results]);
setLoading(false);
};
useEffect(() => {
fetchMovie();
}, [page]);
return (
<div className="App">
<header className="App-header">
<h1>Popular Movies from TMDB</h1>
<div className="movieCardContainer">
{data.map((item) => (
<MovieCard
key={item.id}
title={item.original_title}
description={item.overview}
rating={item.vote_average}
imageURL={item.poster_path}
/>
))}
{loading && <h2>Loading...</h2>}
</div>
</header>
</div>
);
}
export default App;
MovieCard.js
import React from "react";
export const MovieCard = ({ title, description, imageURL, rating }) => {
const imagePath = `https://image.tmdb.org/t/p/w500${imageURL}`;
return (
<div className="movieCard">
<img src={imagePath} height={400} alt={title} />
<div className="movieInfo">
<h3>{title}</h3>
<p>{description}</p>
<p>{rating.toFixed(1)}โญ</p>
</div>
</div>
);
};
Infinite Scroll Implementation
To achieve infinite scrolling, we'll monitor the scrollbar position and trigger data fetching when reaching the bottom.
Detecting Scroll Position
const handleScroll = () => {
if (document.documentElement.scrollHeight - 300 < window.scrollY + window.innerHeight) {
setLoading(true);
}
};
useEffect(() => {
if (loading) setPage((prevPage) => prevPage + 1);
}, [loading]);
Optimizing Performance with Debounce
To prevent excessive function calls, we'll debounce the scroll event:
const debounce = (func, delay) => {
let timeoutId;
return (...args) => {
if (timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
};
window.addEventListener("scroll", debounce(handleScroll, 500));
