Skip to main content

Pagination in React JS Using React Bootstrap without using library

· 9 min read
Kamlesh
Quality Assurance @TestKarts

Introduction

The ability to paginate data is crucial when working with large datasets in web applications. Pagination allows us to divide the data into smaller, more manageable chunks, improving performance and user experience. In this tutorial, we will explore how to implement pagination in a React application. We'll use a sample employee report page to demonstrate the pagination functionality. We will implement a fully working pagination system in a React application without using any external libraries. We will leverage React Bootstrap for styling and create a custom pagination component from scratch.

Table of Contents

Introduction to Pagination

Pagination is a technique used to divide a large dataset into smaller, more manageable portions. It allows users to navigate through the data by displaying a subset of records on each page. Pagination is commonly used in web applications that deal with lists or tables of data.

Preview

Pagination in React JS Using React Bootstrap

Setting up the Project

Before we dive into implementing pagination, let's set up our React project. We'll use Create React App to quickly scaffold our application. Follow the steps below to create a new React project:

  1. Open your terminal and navigate to the desired directory.
  2. Run the following command to create a new React project:
    npx create-react-app pagination-demo
  3. Once the project is created, navigate into the project directory:
    cd pagination-demo
  4. Start the development server:
    npm start
    This command will start the development server and open your application in the browser.

Folder Structure

In your React project's src folder, you would have two files: EmpReports.js and CustomPagination.js.js. These files contain the code for the EmpReports component and the CustomPagination component, respectively.

pagination-demo
├── src
│ ├── EmpReports.js
│ ├── CustomPagination.js

Fetching API Data

In a real-world scenario, you would typically fetch the data from an API. For the purpose of this tutorial, we'll simulate the API data fetch by using a static array. Open the EmpReports.js file and replace the existing useEffect block with the following code:

useEffect(() => {
// Simulating API data fetch
const apiDataFetch = [
// Sample API data objects
];

setApiData(apiDataFetch);
}, []);

This code simulates the API data fetch and sets the fetched data in the apiData state.

Implementing the Employee Reports Page

Let's start implementing the Employee Reports page.

  • In the EmpReports component, we'll display the employee data in a table format with pagination and search box .
  • In the EmpReports.js file and update the return statement as follows:
return (
<div className='fluid container'>
<h2 className='mb-2 fw-50'>EmpReports</h2>
{/* Search input field */}
<input
style={{ width: '200px' }}
className='form-control mb-2'
placeholder='Search'
value={searchFilter}
onChange={handleFilter}
/>
{/* Employee Reports table */}
<Table striped bordered hover id='table'>
<tbody>
<tr>
<th style={{ width: '4%' }}>#</th>
<th>Employee Name</th>
<th>Age</th>
</tr>
{/* Render table rows */}
{paginatedData.length > 0 ? (
paginatedData.map((

item, i) => (
<tr key={i} style={{ background: '#fff' }}>
<td>{(currentPage - 1) * pageSize + i + 1}</td>
<td>{item.Name}</td>
<td>{item.age}</td>
</tr>
))
) : (
<tr>
<td colSpan='3'>No data found</td>
</tr>
)}
</tbody>
</Table>
{/* Render pagination component */}
{filteredData.length > 0 && (
<CustomPagination
itemsCount={filteredData.length}
itemsPerPage={pageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
alwaysShown={true}
/>
)}
</div>
);

This code adds a search input field and a table to display the employee reports. We also conditionally render the pagination component if there is data available.

Filtering Data

Next, let's implement the functionality to filter the data based on the search input. In the EmpReports.js component, add the following code inside the component:

// Filter the data based on search input
const handleFilter = (e) => {
setSearchFilter(e.target.value);
};

// Apply the filter to the data
const filteredData = apiData.filter(
(item) =>
item.Name.toLowerCase().includes(searchFilter.toLowerCase()) ||
item.age.toString().includes(searchFilter)
);

This code handles the search input change and filters the apiData based on the search input. The filtered data is stored in the filteredData state.

Paginating the Data

To implement pagination, we need to slice the filtered data based on the current page and the page size. Add the following code inside the EmpReports.js component:

// Slice the filtered data based on the current page and page size
const paginatedData = filteredData.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);

This code uses the slice method to extract a subset of the filteredData based on the current page and page size. The resulting paginated data is stored in the paginatedData state.

  • Here is the complete code for EmpReports.js. In this example, apiDataFetch is used as a example for fetched data.
src/EmpReports.js
import React, { useEffect, useState } from 'react';
import { Table } from 'react-bootstrap';
import CustomPagination from './CustomPagination';

const EmpReports = () => {
const [apiData, setApiData] = useState([]); // set the api data
const [searchFilter, setSearchFilter] = useState(''); // filter the search
const [currentPage, setCurrentPage] = useState(1); // set the current page
const pageSize = 3; // show row in table
//replace this code with your api
useEffect(() => {
// Simulating API data fetch
const apiDataFetch = [
{ Name: 'John Doe', age: 25 },
{ Name: 'John Doe', age: 25 },
{ Name: 'John Doe', age: 25 },
{ Name: 'John Doe', age: 25 },

{ Name: 'raja1', age: 25 },
{ Name: 'raja2', age: 25 },
{ Name: 'raja3', age: 25 },

{ Name: 'raja', age: 1 },
{ Name: 'raj', age: 3 },
{ Name: 'rajaji', age: 2 },

{ Name: 'paras', age: 2 },
{ Name: 'raja', age: 1 },
{ Name: 'raj', age: 3 },

{ Name: 'rajaji', age: 2 },
{ Name: 'paras', age: 2 },

// Add more objects as needed // or replace
];

setApiData(apiDataFetch);
}, []);

//end heare

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

const handleFilter = (e) => {
setSearchFilter(e.target.value);
};

const filteredData = apiData.filter(
(item) =>
item.Name.toLowerCase().includes(searchFilter.toLowerCase()) ||
item.age.toString().includes(searchFilter)
);

const paginatedData = filteredData.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);

return (
<div className='fluid container'>
<div className='mb-2 fw-50'>EmpReports</div>
<input
style={{ width: "200px" }}
className='form-control mb-2'
placeholder='Search'
value={searchFilter}
onChange={handleFilter}
/>
<Table striped bordered hover id='table'>
<tbody>
<tr>
<th style={{ width: '4%' }}>#</th>
<th>Employee Name</th>
<th>Age</th>
</tr>
{paginatedData.length > 0 ? (
paginatedData.map((item, i) => (
<tr key={i} style={{ background: '#fff' }}>
<td>{(currentPage - 1) * pageSize + i + 1}</td>
<td>{item.Name}</td>
<td>{item.age}</td>
</tr>
))
) : (
<tr>
<td colSpan="3">No data found</td>
</tr>
)}
</tbody>
</Table>
{filteredData.length > 0 &&
<>
<CustomPagination
itemsCount={filteredData.length}
itemsPerPage={pageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
alwaysShown={true}
/>
</>
}
</div>
);
};

export default EmpReports;

Creating the Custom Pagination Component

Now let's create a reusable CustomPagination component that will handle the pagination UI. Create a new file called CustomPagination.js and add the following code:

// Import necessary dependencies
import React, { useEffect } from 'react';
import Pagination from 'react-bootstrap/Pagination';
import PropTypes from 'prop-types';

const CustomPagination = ({
itemsCount,
itemsPerPage,
currentPage,
setCurrentPage,
alwaysShown = true,
}) => {
// Pagination logic goes here

return (
<>
{/* Render the pagination UI */}
</>
);
};

CustomPagination.propTypes = {
itemsCount: PropTypes.number.isRequired,
currentPage: PropTypes.number.isRequired,
setCurrentPage: PropTypes.func.isRequired,
alwaysShown: PropTypes.bool,
};

export default CustomPagination;

This code sets up the basic structure of the CustomPagination.js component and defines the required props.

Styling the Pagination Component

To style the pagination component, we can use the Bootstrap Pagination component. Add the following code inside the CustomPagination.js component:

return (
<>
{isPaginationShown && (
<Pagination>
{/* Previous page button */}
<Pagination.Prev
className={isCurrentPageFirst ? 'disable' : ''}
onClick={onPreviousPageClick}
disabled={isCurrentPageFirst}
/>
{/* Render page numbers */}
{pageNumbers}
{/* Next page button */}
<Pagination.Next
onClick={onNextPageClick}
disabled={isCurrentPageLast}
className={isCurrentPageLast ? 'disable' : ''}
/>
</Pagination>
)}
</>
);

This code uses the Bootstrap Pagination component to render the pagination UI. It includes the previous page button, page numbers, and next page button.

  • Here is the complete code for CustomPagination.js. In this example, apiDataFetch is used as a example for fetched data.
src/CustomPagination.js
import React, { useEffect } from "react";
import Pagination from "react-bootstrap/Pagination";
import PropTypes from "prop-types";

const CustomPagination = ({
itemsCount,
itemsPerPage,
currentPage,
setCurrentPage,
alwaysShown = true
}) => {

const pagesCount = Math.ceil(itemsCount / itemsPerPage);
const isPaginationShown = alwaysShown ? true : pagesCount > 1;
const isCurrentPageFirst = currentPage === 1;
const isCurrentPageLast = currentPage === pagesCount;
const changePage = number => {
if (currentPage === number) return;
setCurrentPage(number);
// scrollToTop();
};
const onPageNumberClick = pageNumber => {
changePage(pageNumber);
};

const onPreviousPageClick = () => {
if (currentPage <= 1) {
return (changePage(currentPage => currentPage = 1));
} else {
changePage(currentPage => currentPage - 1);
}

};

const onNextPageClick = () => {
changePage(currentPage => currentPage + 1);
};

const setLastPageAsCurrent = () => {
if (currentPage > pagesCount) {
pagesCount && setCurrentPage(pagesCount);
}
};

let isPageNumberOutOfRange;

const pageNumbers = [...new Array(pagesCount)].map((_, index) => {
const pageNumber = index + 1;
const isPageNumberFirst = pageNumber === 1;
const isPageNumberLast = pageNumber === pagesCount;
const isCurrentPageWithinTwoPageNumbers =
Math.abs(pageNumber - currentPage) <= 2;

if (
isPageNumberFirst ||
isPageNumberLast ||
isCurrentPageWithinTwoPageNumbers
) {
isPageNumberOutOfRange = false;
return (
<Pagination.Item
activeLabel=""
key={pageNumber}
onClick={() => onPageNumberClick(pageNumber)}
active={pageNumber === currentPage}
>
{pageNumber}
</Pagination.Item>
);
}

if (!isPageNumberOutOfRange) {
isPageNumberOutOfRange = true;
return <Pagination.Ellipsis key={pageNumber} className="muted" />;
}

return null;
});

useEffect(setLastPageAsCurrent, [pagesCount]);

return (
<>
{isPaginationShown && (
<Pagination>
<Pagination.Prev
className={isCurrentPageFirst ? "disable" : ""}
onClick={onPreviousPageClick}
disabled={isCurrentPageFirst}
/>
{pageNumbers}
<Pagination.Next
onClick={onNextPageClick}
disabled={isCurrentPageLast}
className={isCurrentPageLast ? "disable" : ""}
/>
</Pagination>
)}
</>
);
};

CustomPagination.propTypes = {
itemsCount: PropTypes.number.isRequired,
currentPage: PropTypes.number.isRequired,
setCurrentPage: PropTypes.func.isRequired,
alwaysShown: PropTypes.bool
};

export default CustomPagination;

Conclusion

In this tutorial, we explored how to implement pagination in a React application. We started by setting up the project and fetching the API data. Then, we implemented the Employee Reports page with filtering and pagination functionality. We also created a custom pagination component and styled it using Bootstrap.

Pagination is a powerful tool for handling large datasets and improving the performance of your web applications. By implementing pagination, you can provide a better user experience and ensure that your application remains responsive even with substantial amounts of data.

Feel free to customize and enhance the pagination implementation according to your specific requirements. Happy coding!

I hope you find this tutorial helpful! If you have any further questions, feel free to ask.