Infinite scroll is a very popular technique in modern web development.
And it’s no wonder – this feature enhances the user experience by allowing content to load continuously as the user scrolls down the page, without the need to click on «load more» or «next page» buttons.
Given its advantages, it’s no surprise that we find it on so many websites and apps. Would you like to know how it works?
Stay tuned and find out how to implement infinite scroll in React JS, one of the most widely used JavaScript libraries for building dynamic user interfaces.
What is infinite scroll?
Infinite scroll is a web design technique in which additional content is loaded dynamically when the user scrolls to the bottom of the page.
This technique has become popular on social media platforms and news websites, where users prefer to consume content without interruptions.
Why use it in React?
React JS, known for its declarative, component-based approach, is an excellent choice for implementing infinite scroll. Some reasons to use infinite scroll in your React projects include:
- Improves the user experience: Users can continue to browse content without interruption.
- Optimised performance: It only loads the necessary data when the user needs it, which can reduce the initial loading time.
- Ongoing interaction: It keeps users engaged by providing a steady stream of content.
Creating Infinite Scroll in React JS
Implementing infinite scroll in a React JS application may seem like a complex task, but with the right library and tools, it is a fairly straightforward process.
In the following paragraphs, we will describe, step by step, how to create an infinite scroll component in React JS from scratch, using Axios to handle HTTP requests and an `IntersectionObserver` to detect when to load more content.
We’ll cover topics such as setting up the environment, configuring the project, and implementing the logic needed to make your React application more dynamic and fluid.
Preparing the environment
Before you start implementing infinite scrolling in React JS, it is essential to ensure that you have the right development environment.
To do this, you’ll need Node.js and npm installed on your system. Node.js provides the runtime environment for JavaScript outside the browser, and npm is the package manager that will allow you to install the necessary libraries.
You can check whether you already have Node.js and npm installed by running the following commands in your terminal:
node -v
npm -v
«`
If they are not already installed, you can download and install the latest version from Node.js.
Setting up the project in React
Once your environment is set up, the next step is to create a new React project using Create React App.
Create React App is a tool that allows you to set up a React project with all the necessary configurations and pre-installed dependencies.
To create a new project, open your terminal and run the following commands:
npx create-react-app infinite-scroll-react
cd infinite-scroll-react
«`
This will create a new folder called `infinite-scroll-react` with a predefined project structure.
Installing Axios for HTTP requests
In order to load data from an external API, we need a library to make HTTP requests.
Axios is an excellent choice due to its simplicity and efficiency. To install Axios in your React project, run the following command from within your project directory:
npm install axios
«`
Once installed, we can use Axios to make HTTP requests to an API and retrieve the data we need for our infinite scroll:
Creating the infinite scroll component
Having done that, we need to create the component that will handle the infinite scroll.
This component will be responsible for rendering the list of items and handling the loading of new items when the user reaches the bottom of the page.
To do this, create a new file called `InfiniteScroll.js` in your components directory and add the following code:
«`jsx
import React, { useState, useEffect } from ‘react’;
import axios from ‘axios’;
import ItemList from ‘./ItemList’;
const InfiniteScroll = () => {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
useEffect(() => {
const loadItems = async () => {
setLoading(true);
try {
const response = await axios.get(`https://api.example.com/items?page=${page}`);
setItems(prevItems => […prevItems, …response.data]);
} catch (error) {
console.error(«Error fetching data: «, error);
} finally {
setLoading(false);
}
};
loadItems();
}, [page]);
useEffect(() => {
const handleScroll = () => {
if (window.innerHeight + document.documentElement.scrollTop !== document.documentElement.offsetHeight || loading) {
return;
}
setPage(prevPage => prevPage + 1);
};
window.addEventListener(‘scroll’, handleScroll);
return () => window.removeEventListener(‘scroll’, handleScroll);
}, [loading]);
return (
<div>
<ItemList items={items} />
{loading && <p>Loading…</p>}
</div>
);
};
export default InfiniteScroll;
«`
Implementation of infinite scroll logic
In the `InfiniteScroll` component, we have implemented the necessary logic to handle infinite scrolling. Below, we explain how it works:
- Status of the items: We use `useState` to maintain the state of the items to be displayed in the list (`items`), the current page (`page`) and the loading state (`loading`).
- Loading items: We use `useEffect` to load items from an API whenever the page changes. The `loadItems` function is responsible for making the HTTP request and updating the state of the items.
- Handling the scroll event: Another `useEffect` is used to add a scroll event (`scroll`) to the `window` object. The `handleScroll` function checks whether the user has reached the bottom of the page and, if so, increments the current page to load more items.
- Rendering of elements: The `ItemList` component is used to render the list of items. If `loading` is true, a «Loading…» message is displayed whilst the new items are being loaded.
Making HTTP requests with Axios
As we mentioned, we use Axios to make HTTP requests. This allows us to handle requests simply and efficiently.
Let’s see how we use Axios in our component:
«`jsx
import axios from ‘axios’;
const loadItems = async () => {
setLoading(true);
try {
const response = await axios.get(`https://api.example.com/items?page=${page}`);
setItems(prevItems => […prevItems, …response.data]);
} catch (error) {
console.error(«Error fetching data: «, error);
} finally {
setLoading(false);
}
};
«`
1. Import Axios: First, we import Axios into our component.
2. The `loadItems` function: This function is declared within the first `useEffect` and is called every time the page changes. Inside `loadItems`:
- `loading` is set to `true` to indicate that a request is in progress.
- A GET request is made to the API using `axios.get`. The URL includes the page number as a query parameter.
- If the request is successful, we update the status of the elements by concatenating the new elements received with the existing ones.
- If an error occurs during the request, it is logged in the console.
- Finally, `loading` is set to `false` to indicate that the request has finished.
Rendering the data in the component
In the next step, to render the data in our `InfiniteScroll` component, we will use the `ItemList` component that we created earlier.
This component will be responsible for receiving the list of items via props and displaying them in the user interface.
Let’s see how `ItemList` is integrated into `InfiniteScroll`.
Firstly, make sure that the `ItemList` component is correctly implemented to receive and render the items:
«`jsx
import React from ‘react’;
const ItemList = ({ items }) => {
return (
- {item.title}
{items.map(item => (
))}
);
};
export default ItemList;
«`
Next, in the `InfiniteScroll` component, we ensure that `ItemList` receives the items via props:
«`jsx
import React, { useState, useEffect } from ‘react’;
import axios from ‘axios’;
import ItemList from ‘./ItemList’;
const InfiniteScroll = () => {
const [items, setItems] = useState([]);
const [page, setPage] = useState(1);
const [loading, setLoading] = useState(false);
useEffect(() => {
const loadItems = async () => {
setLoading(true);
try {
const response = await axios.get(`https://api.example.com/items?page=${page}`);
setItems(prevItems => […prevItems, …response.data]);
} catch (error) {
console.error(«Error fetching data: «, error);
} finally {
setLoading(false);
}
};
loadItems();
}, [page]);
useEffect(() => {
const handleScroll = () => {
if (window.innerHeight + document.documentElement.scrollTop !== document.documentElement.offsetHeight || loading) {
return;
}
setPage(prevPage => prevPage + 1);
};
window.addEventListener(‘scroll’, handleScroll);
return () => window.removeEventListener(‘scroll’, handleScroll);
}, [loading]);
return (
<div>
<ItemList items={items} />
{loading && <p>Loading…</p>}
</div>
);
};
export default InfiniteScroll;
«`
Implementation of the component in the application
Now that we have implemented and tested our `InfiniteScroll` component, it is time to integrate it into the main application. This is done in the `App.js` file.
The aim is to ensure that `InfiniteScroll` renders correctly and works as expected within the context of the entire application.
Modify `App.js` as follows:
«`jsx
import React from ‘react’;
import InfiniteScroll from ‘./InfiniteScroll’;
function App() {
return (
<div classname="»App»">
<h1>React Infinite Scroll Example</h1>
<InfiniteScroll />
</div>
);
}
export default App;
«`
With this change, the `InfiniteScroll` component will form part of the application’s component tree, allowing the user to experience infinite scrolling functionality whilst navigating the page.
Test and optimise the component
Finally, testing and optimising the component is crucial to ensuring a smooth and seamless user experience. Here are some steps and tips for testing and optimising your infinite scroll:
- Functional tests: Make sure the data loads correctly when you reach the bottom of the page. Also, check that there are no duplicates in the rendered elements. And ensure that the loading status is handled correctly and that the «Loading…» message is displayed when necessary.
- Performance optimisation: Firstly, make sure you disable the scroll event when it is not needed to avoid unnecessary calls. Then implement techniques such as debounce or throttle to limit the number of scroll events being handled. You can use libraries such as Lodash for this.
«`jsx
import _ from ‘lodash’;
useEffect(() => {
const handleScroll = _.throttle(() => {
if (window.innerHeight + document.documentElement.scrollTop !== document.documentElement.offsetHeight || loading) {
return;
}
setPage(prevPage => prevPage + 1);
}, 300);
window.addEventListener(‘scroll’, handleScroll);
return () => window.removeEventListener(‘scroll’, handleScroll);
}, [loading]);
«`
- Error handling: Implement robust error-handling logic to deal with failures in HTTP requests. You can display an error message to the user or attempt to reload the data after a short delay.
«`jsx
const loadItems = async () => {
setLoading(true);
try {
const response = await axios.get(`https://api.example.com/items?page=${page}`);
setItems(prevItems => […prevItems, …response.data]);
} catch (error) {
console.error(«Error fetching data: «, error);
// Optional: Display an error message or try again
} finally {
setLoading(false);
}
};
«`
- Testing: Finally, carry out unit and integration tests to ensure that your component works correctly in different scenarios. Use tools such as Jest and React Testing Library to write tests for your component.
Conclusions
As we have seen, implementing infinite scroll in React JS not only enhances the user experience by enabling smooth, uninterrupted navigation, but also reflects an evolution in the way we interact with web content.
By removing the need for «load more» or «next page» buttons, a more intuitive and engaging experience is created, particularly on platforms where a constant flow of information is crucial, such as social media and news sites.
However, it is important to bear in mind that, whilst infinite scroll can offer many advantages, its implementation must be careful and well-planned.
Performance optimisation, proper error handling and thorough testing are key to ensuring that this functionality not only works correctly, but also provides added value to the user without compromising the application’s efficiency.
Ultimately, the use of infinite scroll in React JS highlights this library’s ability to handle dynamic and responsive user interfaces.
By mastering techniques such as infinite scroll, developers can create more modern and user-friendly web applications, meeting users’ growing expectations regarding accessibility and usability in today’s digital environment.


