One of the major challenges we face as frontend developers is to efficiently manage large sets of data. “Efficiently” here means managing the data in a way that doesn’t affect the user experience negatively. The common way of handling this is with Pagination but the problem with pagination is that it becomes clunky and delivers a poor user experience as the data grows.
In this guide, we’ll use lazy loading which is better and more friendly than using the conventional custom loading with hooks, and then we will use the user-friendly substitute for pagination, infinite scroll, to solve this challenge.
You need to have the following to flow with this guide:
- Knowledge of JavaScript and React
- Nodejs >=v14 installed
We will be implementing a card component and populating it with data so we can test the infinite scrolling. The complete code is on Codesandbox.
Let’s set up our react application by running the command below:
npx create-react-app lazy-loading-infinite-scroll
We will be using the react-bootstrap
package for styling our card components. Install it by running this command on your terminal:
npm install react-bootstrap bootstrap
Create a component
folder from the src
directory and create a CardComponent.jsx
file. Run this command to do that:
cd src
mkdir components && cd components
touch CardComponent.jsx
Code language: CSS (css)
Add this code snippet to CardComponent.jsx
//CardComponent.jsx
import { Card, Button, Container, Col, Row } from 'react-bootstrap'
export default function CardComponent() {
return (
<Container>
<Row>
<Col md={4}>
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="https://images.unsplash.com/photo-1652512456007-e16ac46f1879?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1100&q=80" />
<Card.Body>
<Card.Title>card title</Card.Title>
<Card.Text>
this is an infinite scroll Up
</Card.Text>
<Button variant="primary">Up</Button>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
)
}
Code language: JavaScript (javascript)
Here, we use react-bootstrap components to implement our Card Component. If you’ve noticed, we are not importing React, cause it’s not needed anymore.
Let’s head over to App.js
and register our card component. Add the code snippet below:
//App.js
import 'bootstrap/dist/css/bootstrap.min.css';
import { lazy, Suspense } from 'react'
const CardComponent = lazy(() => import("./components/CardComponent"))
function App() {
return (
<div>
<h1>React Lazy Loading with Infinite Scroll</h1>
<Suspense fallback={<div>isLoading...</div>}>
<CardComponent />
</Suspense>
</div>
);
}
export default App;
Code language: JavaScript (javascript)
Firstly, we start by importing bootstrap CSS so it can be accessed globally in the project.
Next, we use the React.lazy
function from React which takes a function that calls a dynamic import()
. This function must return a Promise which resolves to a module with a default export containing a React component.
The lazy component (CardComponent
in our case) will then be rendered inside the Suspense Component. The Suspense component allows us to have a fallback function that will be used to render a loader before the lazy components finish loading.
Let’s now run our app. Run this command on your terminal
npm run start
You should see something like this:
If you’ve gotten to this stage, you’re Awesome! Now we’ve handled Lazy loading, let’s implement Infinite scroll.
Now that lazy loading is implemented on the Card component, we will implement infinite scroll for the cards, such that once the user reaches the bottom of the page, it automagically adds datasets or makes an API call without the need for pagination buttons.
First, we will create some mock data for our cards. This will be the dataset that will be used to loop through and display on the Card components. Create a mock.js
file in the source directory and paste these lines of code
//mock.js
export const cardData = [{
title: "card title",
buttonName: "Down",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "Up",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "Left",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "card title",
buttonName: "right",
description: "this is an infinite scroll"
}
]
Code language: JavaScript (javascript)
Next, navigate to App.js
and import the mock data. Modify the App.js
and add this line
//App.js
import { cardData } from './mock';
Code language: JavaScript (javascript)
Next, we will pass cardData
as props to our CardWrapper
Component. Update this line in App.js
with this
//App.js
<CardComponent cardData={cardData} />
Code language: HTML, XML (xml)
Now we have passed our data to the Card component, let’s implement the infinite scroller.
We will be using an external react library called react-infinite-scroller
.
First, we need to install the package. To do that run the command below
npm install react-infinite-scroller
Next is to implement the infinite scroll which will be inside the card components. Navigate to Card component and update the code with the below.
import { useState } from 'react';
import { Card, Button, Container, Col, Row } from 'react-bootstrap'
import InfiniteScroll from 'react-infinite-scroller'; //new
export default function CardComponent({ cardData }) {
const [data, setData] = useState(cardData) //new
const loading = async () => { //new
const newCardData = [
{
title: "New card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "New card title",
buttonName: "right",
description: "this is an infinite scroll"
},
{
title: "New card title",
buttonName: "right",
description: "this is an infinite scroll"
}
]
if (data.length <= 20) { //new
await setData((data) => [...data, ...newCardData])
}
}
return (
<Container>
<InfiniteScroll //new
pageStart={0}
loadMore={loading}
hasMore={true || false}
loader={<div className="loader" key={0}>Loading ...</div>}
>
<Row>
{data.map((data, index) => ( //new
<Col md={4} key={index}>
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="https://images.unsplash.com/photo-1652512456007-e16ac46f1879?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1100&q=80" />
<Card.Body>
<Card.Title>{data.title}</Card.Title>
<Card.Text>
{data.description}
</Card.Text>
<Button variant="primary">{data.buttonName}</Button>
</Card.Body>
</Card>
</Col>
)
)}
</Row>
</InfiniteScroll>
</Container>
)
}
Code language: JavaScript (javascript)
Let’s break down this code snippet into chunks.
First, we imported the InfiniteScroll
component from react-infinite-scroller
. The InfiniteScroll
component accepts parameters as follows:
pageStart**={0}** = This accept the page number, mostly when connecting to an API endpoint loadMore**={ }** = This is accept the function that will run when the scroll reaches bottom hasMore**={true || false}** = This accept a boolean value loader**={}** = this allows us to pass a loader.
Next, we set the cardData
we passed from our parent component with React useState hook.
Then we have the async loading function that pushes more values to the dataset since we are not using getting data from an API.
Finally, we loop through the cardData
and use it in the template.
Save and run the app. You should get something like this:
Infinite scrolling is essential for large datasets cause the user experience is smooth compared to pagination. In this tutorial, we implemented infinite scroll with react-infinite-scroller and lazy loading react components with React.lazy
and Suspense
.
Happy Coding!