How to Implement Lazy Loading with Infinite Scroll

Christian Nwamba

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.

Pre-requisites

You need to have the following to flow with this guide:

  • Knowledge of JavaScript and React
  • Nodejs >=v14 installed

What we will be building?

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.

Getting Started

Let’s set up our react application by running the command below:

1//javascript
2npx create-react-app lazy-loading-infinite-scroll

Implementing the Card component

We will be using the react-bootstrap package for styling our card components. Install it by running this command on your terminal:

1npm install react-bootstrap bootstrap

Create a component folder from the src directory and create a CardComponent.jsx file. Run this command to do that:

1#bash
2cd src
3mkdir components && cd components
4touch CardComponent.jsx

Add this code snippet to CardComponent.jsx

1//CardComponent.jsx
2import { Card, Button, Container, Col, Row } from 'react-bootstrap'
3export default function CardComponent() {
4 return (
5 <Container>
6 <Row>
7 <Col md={4}>
8 <Card style={{ width: '18rem' }}>
9 <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" />
10 <Card.Body>
11 <Card.Title>card title</Card.Title>
12 <Card.Text>
13 this is an infinite scroll Up
14 </Card.Text>
15 <Button variant="primary">Up</Button>
16 </Card.Body>
17 </Card>
18 </Col>
19 </Row>
20 </Container>
21 )
22}

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:

1//App.js
2import 'bootstrap/dist/css/bootstrap.min.css';
3import { lazy, Suspense } from 'react'
4
5const CardComponent = lazy(() => import("./components/CardComponent"))
6
7function App() {
8 return (
9 <div>
10 <h1>React Lazy Loading with Infinite Scroll</h1>
11 <Suspense fallback={<div>isLoading...</div>}>
12 <CardComponent />
13 </Suspense>
14 </div>
15 );
16}
17export default App;

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

1npm 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.

Implementing 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

1//mock.js
2export const cardData = [{
3 title: "card title",
4 buttonName: "Down",
5 description: "this is an infinite scroll"
6},
7{
8 title: "card title",
9 buttonName: "Up",
10 description: "this is an infinite scroll"
11},
12{
13 title: "card title",
14 buttonName: "Left",
15 description: "this is an infinite scroll"
16},
17{
18 title: "card title",
19 buttonName: "right",
20 description: "this is an infinite scroll"
21},
22{
23 title: "card title",
24 buttonName: "right",
25 description: "this is an infinite scroll"
26},
27{
28 title: "card title",
29 buttonName: "right",
30 description: "this is an infinite scroll"
31},
32{
33 title: "card title",
34 buttonName: "right",
35 description: "this is an infinite scroll"
36},
37{
38 title: "card title",
39 buttonName: "right",
40 description: "this is an infinite scroll"
41},
42{
43 title: "card title",
44 buttonName: "right",
45 description: "this is an infinite scroll"
46}
47]

Next, navigate to App.js and import the mock data. Modify the App.js and add this line

1//App.js
2import { cardData } from './mock';

Next, we will pass cardData as props to our CardWrapper Component. Update this line in App.js with this

1//App.js
2<CardComponent cardData={cardData} />

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

1#bash
2npm 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.

1import { useState } from 'react';
2import { Card, Button, Container, Col, Row } from 'react-bootstrap'
3import InfiniteScroll from 'react-infinite-scroller'; //new
4
5export default function CardComponent({ cardData }) {
6 const [data, setData] = useState(cardData) //new
7
8 const loading = async () => { //new
9 const newCardData = [
10 {
11 title: "New card title",
12 buttonName: "right",
13 description: "this is an infinite scroll"
14 },
15 {
16 title: "New card title",
17 buttonName: "right",
18 description: "this is an infinite scroll"
19 },
20 {
21 title: "New card title",
22 buttonName: "right",
23 description: "this is an infinite scroll"
24 }
25 ]
26 if (data.length <= 20) { //new
27 await setData((data) => [...data, ...newCardData])
28 }
29 }
30
31return (
32 <Container>
33 <InfiniteScroll //new
34 pageStart={0}
35 loadMore={loading}
36 hasMore={true || false}
37 loader={<div className="loader" key={0}>Loading ...</div>}
38 >
39 <Row>
40 {data.map((data, index) => ( //new
41 <Col md={4} key={index}>
42 <Card style={{ width: '18rem' }}>
43 <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" />
44 <Card.Body>
45 <Card.Title>{data.title}</Card.Title>
46 <Card.Text>
47 {data.description}
48 </Card.Text>
49 <Button variant="primary">{data.buttonName}</Button>
50 </Card.Body>
51 </Card>
52 </Col>
53 )
54 )}
55 </Row>
56 </InfiniteScroll>
57 </Container>
58)
59}

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:

Conclusion

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!

Christian Nwamba

Developer Advocate at AWS

A software engineer and developer advocate. I love to research and talk about web technologies and how to delight customers with them.