DEV Community

Cover image for From Frontend to Backend: Build Scalable Pagination for Web Applications
Md Nazmus Sakib
Md Nazmus Sakib

Posted on

From Frontend to Backend: Build Scalable Pagination for Web Applications

Pagination is an essential feature in any application that handles large datasets. It improves performance, enhances user experience, and ensures smooth navigation across pages. This guide provides a step-by-step implementation of pagination for a React frontend (with Tailwind CSS and Vite) and a Node.js/Express.js backend with Next.js API routes and MongoDB.


Why Pagination is Important?

  1. Performance Optimization: Reduces data load on both the client and server.
  2. Improved User Experience: Allows users to view data in manageable chunks.
  3. Scalability: Makes the app efficient even when datasets grow over time.
  4. Better Resource Management: Reduces memory usage on the frontend and backend.

Tech Stack Overview

  • Frontend: React.js, Tailwind CSS, Vite (for a fast development experience).
  • Backend: Node.js, Express.js, Next.js API routes.
  • Database: MongoDB (NoSQL database).
  • Tools: Axios for HTTP requests.

Step-by-Step Implementation

Backend: Building Pagination API with Node.js and MongoDB

1. Set Up Express.js Server

Ensure you have Node.js installed, then set up a new Express.js server.

mkdir pagination-backend
cd pagination-backend
npm init -y
npm install express mongoose dotenv
Enter fullscreen mode Exit fullscreen mode

2. Create Server and MongoDB Connection

Set up a simple server with MongoDB.

server.js

const express = require('express');
const mongoose = require('mongoose');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT || 5000;

// MongoDB Connection
mongoose.connect(process.env.MONGO_URI)
  .then(() => console.log('MongoDB connected'))
  .catch(err => console.error(err));

app.use(express.json());

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Add your MongoDB URI in a .env file:

MONGO_URI=mongodb://localhost:27017/pagination_demo
Enter fullscreen mode Exit fullscreen mode

3. Create a Sample Model

Define a sample data schema for storing records.

models/User.js

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  name: String,
  email: String,
  createdAt: { type: Date, default: Date.now }
});

module.exports = mongoose.model('User', UserSchema);
Enter fullscreen mode Exit fullscreen mode

4. Create Pagination Route

Add a route to return paginated results.

routes/users.js

const express = require('express');
const router = express.Router();
const User = require('../models/User');

// GET Paginated Data
router.get('/users', async (req, res) => {
  const page = parseInt(req.query.page) || 1; // Default to page 1
  const limit = parseInt(req.query.limit) || 10; // Default 10 items per page

  try {
    const startIndex = (page - 1) * limit;
    const total = await User.countDocuments();

    const users = await User.find().skip(startIndex).limit(limit);

    res.status(200).json({
      totalPages: Math.ceil(total / limit),
      currentPage: page,
      data: users,
    });
  } catch (error) {
    res.status(500).json({ message: error.message });
  }
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

5. Add the Route to Server

In server.js, include the route:

const usersRoute = require('./routes/users');
app.use('/api', usersRoute);
Enter fullscreen mode Exit fullscreen mode

6. Test the API

Run the server:

node server.js
Enter fullscreen mode Exit fullscreen mode

Test with tools like Postman or the browser:

  • GET http://localhost:5000/api/users?page=1&limit=10

⚛️ Frontend: Implement Pagination with React, Tailwind CSS, and Vite

1. Set Up React with Vite

npm create vite@latest frontend
cd frontend
npm install
npm install axios react-router-dom
Enter fullscreen mode Exit fullscreen mode

2. Fetch Paginated Data

Create a React component to fetch paginated data from the backend API.

components/UserList.jsx

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const UserList = () => {
  const [users, setUsers] = useState([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);

  const fetchUsers = async (page) => {
    const { data } = await axios.get(
      `http://localhost:5000/api/users?page=${page}&limit=10`
    );
    setUsers(data.data);
    setTotalPages(data.totalPages);
    setCurrentPage(page);
  };

  useEffect(() => {
    fetchUsers(1);
  }, []);

  const handlePageChange = (page) => fetchUsers(page);

  return (
    <div className="p-5">
      <h1 className="text-2xl font-bold mb-4">Paginated User List</h1>
      <ul>
        {users.map((user) => (
          <li key={user._id} className="border p-2 mb-2">
            {user.name} - {user.email}
          </li>
        ))}
      </ul>

      {/* Pagination Buttons */}
      <div className="flex gap-2 mt-4">
        {[...Array(totalPages).keys()].map((_, index) => (
          <button
            key={index}
            onClick={() => handlePageChange(index + 1)}
            className={`px-4 py-2 border rounded ${
              currentPage === index + 1 ? 'bg-blue-500 text-white' : ''
            }`}
          >
            {index + 1}
          </button>
        ))}
      </div>
    </div>
  );
};

export default UserList;
Enter fullscreen mode Exit fullscreen mode

3. Add Tailwind CSS

Install Tailwind CSS:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

Configure tailwind.config.js:

module.exports = {
  content: ["./index.html", "./src/**/*.{js,jsx}",],
  theme: {
    extend: {},
  },
  plugins: [],
};
Enter fullscreen mode Exit fullscreen mode

Add Tailwind directives to index.css:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

4. Use the UserList Component

Integrate the component in App.jsx:

import React from 'react';
import UserList from './components/UserList';

function App() {
  return (
    <div>
      <UserList />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Example Output

The app fetches paginated data from the server and displays it with buttons to navigate pages.


Key Takeaways

  • The backend calculates skip and limit to fetch specific records.
  • The frontend uses state to manage pagination UI and fetches new data when pages change.
  • Tailwind CSS makes styling pagination buttons fast and clean.

Final Notes

This implementation gives you a clean and scalable way to handle pagination for large datasets in a MERN stack application.

Happy coding!

Top comments (0)