Load more in React, Node.js & MongoDB

Previously, we wrote 2 articles on how to add a “load more” button. First article uses Node.js and MongoDB and EJS for frontend and second article uses PHP and MySQL. In this article, we will show you, how you can create a “load more” button in React with Node.js and MongoDB as your backend. This is the refined version of previous load more tutorial in Node.js and MongoDB.

First, let me show you all the code. Then I will explain everything.

React

function App() {

    // Set current page
    const [page, setPage] = React.useState(1);

    // Data array
    const [users, setUsers] = React.useState([]);

    // Check if there are more pages
    const [hasMorePages, setHasMorePages] = React.useState(false);

    async function loadMore() {
        // Creating a built-in AJAX object
        var ajax = new XMLHttpRequest();

        // Tell the method, URL of request and make is asynchronous
        ajax.open("POST", "http://localhost:3000/fetch-users", true);

        // Detecting request state change
        ajax.onreadystatechange = function () {

            // Called when the response is successfully received
            if (this.readyState == 4) {

                if (this.status == 200) {
                    // For debugging purpose only
                    // console.log(this.responseText);

                    // Converting JSON string to Javasript array
                    var response = JSON.parse(this.responseText);
            
                    // Get data from API
                    const newArr = response.users;

                    // ❌ Less efficient, more readable
                    // Get current data
                    /*const tempArr = [ ...users ];

                    // Loop through all new records
                    for (let a = 0; a < newArr.length; a++) {
                        // And add them in existing array
                        tempArr.push(newArr[a]);
                    }

                    // Update state variable
                    setUsers(tempArr);*/

                    // ✅ Efficient way
                    setUsers([...users, ...newArr]); 

                    // Set if there are more pages
                    setHasMorePages(response.hasMorePages);
                }
            }
        };

        // Create form data object
        const formData = new FormData();

        // Attach current page number
        formData.append("page", page);

        // Send the request
        ajax.send(formData);
    }

    // Run function when page value updates
    React.useEffect(function () {
        loadMore();
    }, [page]);

    return (
        <>
            {/* Display data */}

            { users.map(function (user) {
                return (
                    <p key={ `user-${ user._id }` }>{ user.name }</p>  
                );
            }) }

            {/* Show load more button if there are more pages */}

            { hasMorePages && (
                <button type="button"
                    onClick={ function () {
                        // Increment page value
                        // It will automatically call the loadMore function from useEffect hook
                        setPage(page + 1);
                    } }>Load more</button>
            ) }
        </>
    );
}

Here, we are displaying all the data we are getting from API. We are displaying the “load more” button only if there are more pages required. We created a React.useEffect hook and calling the loadMore function everytime the page value gets updated. It will automatically gets called first time when the page loads. After that, every time you click the “Load more” button, we are simply incrementing the page value by 1. It will trigger the React.useEffect hook, thus calling the loadMore function again.

From API, we will receive the data that will be an array, and a boolean variable that tells if there are more pages required. Based on the latter, we will show or hide the “Load more” button. If there are more pages required, you can keep pressing load more button. When there are no more records in the database, then the load more button will be removed.

When the response from API is received, we are appending the new data in our existing data array. The way to do that in React is different. First, we need to create a shallow copy of our existing array using spread operator: const tempArr = [ …users ]; Then we need to loop through all new data received from API, and push it in your shallow copy of array. Finally, we will update our state variable and will render the new data.

For rendering, we are using Javascript map function to iterate over an array. In each paragraph, we should have a unique key value for React to identify each element uniquely. In order to create a unique key, we are using user ID, and we are displaying user name in each paragraph. This is create a “load more” button in our React component. In next step, we will create it’s API.

Node.js & MongoDB

// Run command in your terminal:
// npm install express http mongodb cors express-formidable
const express = require("express");
const app = express();
const http = require("http").createServer(app);

const mongodb = require("mongodb");
const ObjectId = mongodb.ObjectId;
const MongoClient = mongodb.MongoClient;

const cors = require("cors");
app.use(cors("http://localhost/load-more.html"));

// Native way to allow CORS
/*// Add headers before the routes are defined
app.use(function (req, res, next) {
    // Website you wish to allow to connect
    res.setHeader("Access-Control-Allow-Origin", "*");
    // Request methods you wish to allow
    res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
    // Request headers you wish to allow
    res.setHeader("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Authorization");
    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader("Access-Control-Allow-Credentials", true);
    // Pass to next layer of middleware
    next();
});*/

const expressFormidable = require("express-formidable");
app.use(expressFormidable({
    multiples: true
}));

const port = process.env.PORT || 3000;
const databaseName = "test"
const MONGO_URI = process.env.MONGO_URI || "mongodb://127.0.0.1:27017";

http.listen(port, async function () {
    console.log("Server started");
    
    const client = new MongoClient(MONGO_URI);
    try {
        await client.connect();
        const db = client.db(databaseName);
        console.log("Database connected.");

        // Seeding the data in database
        /*const usersCount = await db.collection("users").countDocuments({});
        if (usersCount == 0) {
            await db.collection("users")
                .insertMany([
                    { name: "Adnan" },
                    { name: "Afzal" },
                    { name: "Ahmad" },
                    { name: "Khalid" },
                    { name: "Tariq" },
                ]);
        }*/

        app.post("/fetch-users", async function (request, result) {
            const limit = 1;
			const page = parseInt(request.fields.page || 1);
			const skip = (page - 1) * limit;
			
			const users = await db.collection("users")
                .find({})
                .sort({
                    _id: 1
                })
                .skip(skip)
                .limit(limit)
                .toArray();

            const usersArr = [];
            for (let a = 0; a < users.length; a++) {
                const obj = {
                    _id: users[a]._id || "",
                    name: users[a].name || ""
                };

                usersArr.push(obj);
            }

			const totalCount = await db.collection("users").countDocuments({});
    		const hasMorePages = (page * limit) < totalCount;

			result.json({
				status: "success",
				message: "Data has been fetched.",
				users: users,
				hasMorePages: hasMorePages
			});
		});
    } catch (exp) {
        console.log(exp.message);
    }
});

Here, we are first starting our server and connecting with MongoDB database. We created an API that accepts the page number as parameter. If the page number is not provided, then the default value of it will be 1. We are setting the limit to 1 for testing. We subtract 1 from current page value and multiply it by the limit, it will give use the number of records we need to skip.

Then we are fetching the data from database using skip and limit. Your document might have a lot of fields, so we created an obj to only return those fields that are need for this API. Finally, in order to check if there is a need for more pages, we first need to find the total number of records in our collection. We can then check if it is greater than the product of limit and page variable. If it is greater, it means there are still more records in the database.

That’s how you can create a “load more” button in React as your frontend and Node.js and MongoDB as your backend. If you face any problem in following this, kindly do let me know.

Load more Node JS button with Mongo DB

In this tutorial, we are going to teach you how you can create a load more Node JS button with MongoDB in your web project. “Load more” means that we will be displaying a few records, let’s say 5 when the page loads. Then we will display a button that when clicked will fetch the next 5 records. It is similar to the Facebook infinite scroll, where when you reach the end of the page, it automatically fetched the next posts. If you prefer a video tutorial over a textual tutorial, you can find it below:

Setup the server

Make sure you have installed Node JS and Mongo DB in your system. To view the data in Mongo DB, you will need a software called Mongo DB Compass. That can be installed during Mongo DB installation. Using Mongo DB Compass, create a database named “loadmore_nodejs_mongodb”. Inside this database, you need to create a collection named “users”. Inside this collection, you can add 10 records for testing. I have added the name and age of each user, the ID is automatically generated by Mongo DB.

Then you need to create an empty folder anywhere on your computer. And create a new file inside it named “server.js”. At the same time, open your command prompt or Terminal in this folder. You can run the following command to enter this folder:

cd "path of folder"

While being inside the folder, run the following command to initialize it as an NPM:

npm init

After that, you need to install some modules using the following command:

npm install express http mongodb ejs express-formidable
  • We will be using an express framework.
  • HTTP module will be used to start the server at a specific port.
  • Mongo DB module will be used to connect and interact with the Mongo DB database.
  • EJS will be used to render HTML files.
  • Express formidable will be used to receive HTTP POST values, which we will be sending from AJAX.

If you do not have a nodemon module you can install it with this command:

npm install -g nodemon

Nodemon command helps you to automatically restart the server if there is any change in the server.js file. Now in server.js, initialize express framework. Then create an HTTP server object and start the server at port 3000.

// initialize express framework
var express = require("express");
var app = express();
 
// create http server
var http = require("http").createServer(app);

// start the server
http.listen(3000, function () {
    console.log("Server started at port 3000");
});

Run nodemon command to start the server.

nodemon server.js

Connecting Node JS with Mongo DB

Now we need to connect our Node JS Express app with Mongo DB. We have already installed the Mongo DB module. Now we need to include the Mongo DB and Mongo Client objects. Place the following lines in your server.js file before calling the HTTP listen function:

// include mongo DB module
var mongodb = require("mongodb");
var mongoClient = mongodb.MongoClient;

Now after line 10 from previous code, place the following lines to connect with database:

// connect with mongo DB server and database
mongoClient.connect("mongodb://localhost:27017", {
    useUnifiedTopology: true
}, function (error, client) {
    var database = client.db("loadmore_nodejs_mongodb");
    console.log("Database connected.");
});

Display HTML file

Now we need to show an empty table where data will be populated dynamically. We will be using EJS to render the HTML file. First, we need to tell our Express app that we will be using the EJS engine. So add the following lines before connecting the HTTP server in server.js:

// set the view engine as EJS for displaying HTML files
app.set("view engine", "ejs");

Now we need to create a GET route that when accessed from the browser will display an HTML page. Place the following lines after line 6 from the previous code:

// create a GET HTTP route to show page
app.get("/", function (request, result) {
    // render an HTML page
    result.render("index");
});

Now we need to create a folder named “views” and inside this folder, create a file named “index.ejs”. Inside this file, we will create a table, and give an ID to the <tbody> because we will be displaying data dynamically. And also a load more button.

<!-- views/index.ejs -->

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Number</th>
            <th>Age</th>
        </tr>
    </thead>

    <tbody id="data"></tbody>
</table>

<button type="button" onclick="getData();">
    Load More
</button>

Now you can access it by entering the following URL in your browser:

http://localhost:3000/

Get data from Mongo DB

Now we need to fetch data from the database in which a way that it will get 2 records each time a button is clicked. But the first 2 records will be fetched when the page loads. So create a script tag and create a variable that will be incremented each time that button is pressed. This variable will be used to skip the records to fetch the next ones.

<script>

    // Starting position to get new records
    var startFrom = 0;

    window.addEventListener("load", function () {
        // Calling the function on page load
        getData();
    });

</script>

Now we need to create that getData() function in index.ejs file. This will send an AJAX request to the route “load-more” with a method POST. We will also attach our startFrom variable with the AJAX object (line 45). When the response is successfully received from the server (line 15), it will be in a JSON string. So we convert that into Javascript arrays and objects (line 20). Then we are appending the newly fetched data in our tbody tag. And finally, we are incrementing the startFrom variable with the number of records we want to show in each AJAX call.

// This function will be called every time a button pressed 
function getData() {
    // Creating a built-in AJAX object
    var ajax = new XMLHttpRequest();

    // tell the method and URL of request
    ajax.open("POST", "http://localhost:3000/load-more", true);

    // Detecting request state change
    ajax.onreadystatechange = function () {

        // Called when the response is successfully received
        if (this.readyState == 4) {

            if (this.status == 200) {
                // For debugging purpose only
                // console.log(this.responseText);

                // Converting JSON string to Javasript array
                var data = JSON.parse(this.responseText);
                var html = "";
         
                // Appending all returned data in a variable called html
                for (var a = 0; a < data.length; a++) {
                    html += "<tr>";
                        html += "<td>" + data[a]._id + "</td>";
                        html += "<td>" + data[a].name + "</td>";
                        html += "<td>" + data[a].age + "</td>";
                    html += "</tr>";
                }
         
                // Appending the data below old data in <tbody> tag
                document.getElementById("data").innerHTML += html;

                // number of records you want to show per page
                var limit = 2;
         
                // Incrementing the offset so you can get next records when that button is clicked
                startFrom = startFrom + limit;
            }
        }
    };

    var formData = new FormData();
    formData.append("startFrom", startFrom);

    // Actually sending the request
    ajax.send(formData);
}

Now we need to create a POST route in our server.js. Before creating a POST route, we need to tell our Express app that we will be using the Express-Formidable module to get values (e.g. startFrom) from AJAX requests. So paste the following lines before starting HTTP server:

// server.js

// used to get POST field values
var formidable = require("express-formidable");
app.use(formidable());

Now write the following lines after the Mongo DB is connected:

// create a POST HTTP route to get data
app.post("/load-more", async function (request, result) {
 
    // number of records you want to show per page
    var limit = 2;
 
    // get records to skip
    var startFrom = parseInt(request.fields.startFrom);
 
    // get data from mongo DB
    var users = await database.collection("users").find({})
        .sort({ "id": -1 })
        .skip(startFrom)
        .limit(limit)
        .toArray();
 
    // send the response back as JSON
    result.json(users);
});

If you run the code now, you will see 2 records when the page loads. On clicking the load more button, 2 more records will be fetched, and so on.

Styling the table – CSS

At this point, you have successfully created a feature where you can display a few records when the page loads. And further records when user clicks a “load more” button. But we can give a few styles just to make it look good. The following styles will:

  • Give 1-pixel black border to the table and all its headings and data tags.
  • border-collapse will merge all the borders into one.
  • We are giving padding (distance between border and content) to all headings and data tags.
  • Give some margin from the bottom to the table to have some space between the table and load more button.
table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
}
th, td {
    padding: 25px;
}
table {
    margin-bottom: 20px;
}

Now that our load more Node JS button is fully functional. We can also try another approach that is usually called “Infinite scroll”.

Infinite scroll

You can also use an “infinite scroll” like Facebook. Instead of displaying a button to load more data, more data will be fetched when the user scrolled to the bottom. No need to change the Node JS code that we used to load more button. For that, first you need to include jQuery.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Then you can replace your window onload event listener with the following:

var loadMore = true;

window.addEventListener("load", function () {
    // Calling the function on page load
    getData();

    $(window).bind('scroll', function() {
        if(!loadMore && $(window).scrollTop() >= $('#data').offset().top + $('#data').outerHeight() - window.innerHeight) {
            // console.log('end reached');
            loadMore = true;
            getData();
        }
    });
});

And finally in your ajax.onreadystatechange listener, when you successfully append the data in the <tbody> tag, keep the infinite scroll working if there are more records.

if (data.length > 0) {
    loadMore = false;
}

So that’s how you can create a load more Node JS button with Mongo DB.

[wpdm_package id=’1251′]

Load more data using AJAX – PHP

Learn how you can show a “Load more” button using AJAX, PHP and MySQL. No external library has been used in this tutorial.

What is “Load more” button ?

By “Load more” we mean creating a button that allows you to show only 10 or 20 records and on clicking that button will fetch next 10 records from database without having to refresh the page. This function is heavily used in tech giant Facebook where older posts are fetched by scrolling without refreshing the page.

We will be using a sample database called classicmodels, it is attached in the source files below.

Create layout

We will be using employees table and displaying employeeNumber, firstName, lastName and email fields. A unique ID should be provided to <tbody> which will be used to append data using Ajax.

<table>
    <thead>
        <tr>
            <th>Number</th>
            <th>First name</th>
            <th>Last name</th>
            <th>Email</th>
        </tr>
    </thead>

    <tbody id="data"></tbody>
</table>

<button type="button" onclick="getData();">
    Load More
</button>

Display initial records

We are displaying 10 records in each step and we will need just 1 variable for this. start to tell the starting position of fetching data and it will be incremented in each step.

<script>
    // Starting position to get new records
    var start = 0;

    // This function will be called every time a button pressed 
    function getData() {
        // Creating a built-in AJAX object
        var ajax = new XMLHttpRequest();

        // Sending starting position
        ajax.open("GET", "Http.php?start=" + start, true);

        // Actually sending the request
        ajax.send();

        // Detecting request state change
        ajax.onreadystatechange = function () {

            // Called when the response is successfully received
            if (this.readyState == 4 && this.status == 200) {

                // For debugging purpose only
                console.log(this.responseText);
            }
        };
    }

    // Calling the function on page load
    getData();
</script>

At this point if you run the program, you will see an empty table and a button, now you need to create Http.php file to handle each request.

Handling AJAX request – PHP

Create a new file and name it Http.php, in this file we will simply get the offset (start variable) and display the records based on that value.

<?php

// Connecting with database
$connection = mysqli_connect("localhost", "root", "", "classicmodels");

// Getting offset to show next records
$start = $_GET["start"];

// Executing the query based on $start variable
$sql = "SELECT * FROM employees LIMIT $start, 10";
$result = mysqli_query($connection, $sql);

// Storing all returned records in an array
$data = array();
while ($row = mysqli_fetch_object($result))
    array_push($data, $row);

// Sending response back to AJAX
echo json_encode($data);

Now if you view your browser console, you will see some JSON string data when the page loads.

Appending records in table

Now you need to convert that JSON string into Javascript array and append in <tbody> tag. Paste the following code back in your index.php file:

ajax.onreadystatechange = function () {
    if (this.readyState == 4 && this.status == 200) {
        console.log(this.responseText);
        
        // Converting JSON string to Javasript array
        var data = JSON.parse(this.responseText);
        var html = "";

        // Appending all returned data in a variable called html
        for (var a = 0; a < data.length; a++) {
            html += "<tr>";
                html += "<td>" + data[a].employeeNumber + "</td>";
                html += "<td>" + data[a].firstName + "</td>";
                html += "<td>" + data[a].lastName + "</td>";
                html += "<td>" + data[a].email + "</td>";
            html += "</tr>";
        }

        // Appending the data below old data in <tbody> tag
        document.getElementById("data").innerHTML += html;

        // Incrementing the offset so you can get next records when that button is clicked
        start = start + 10;
    }
};

So for example, first time you will get employees from 1 to 10 and next time you hit load more button you will get employees from 11 to 20 and so on.

That’s how you can show a “Load more” button using AJAX, PHP and MySQL. You can also create a load more button in Node JS and Mongo DB. Learn from here how you can do that.

[wpdm_package id=’138′]