How To Build Custom Pagination Component In React Js

In this article, we will learn how to build a custom Pagination in React.js.

Now, let’s first create a React application with the following command.

npx create-react-app react-pagination

Our dependencies must then be installed. We’ll just use a simple extra dependency named classnames to handle multiple classNames conditionally.

npm install classnames
How to Implement the usePagination Hook
  • Our pagination hook must return an array with the number range to be shown in our pagination component.
  • When currentPage, pageSize, siblingCount, or totalCount changes, the computation logic must be re-run.
  • The hook’s total number of things should remain consistent. If the length of the range array changes as the user interacts with the component, we won’t have to resize it.

let’s create a file called usePagination.js in our project.

export const usePagination = ({
  totalCount,
  pageSize,
  siblingCount = 1,
  currentPage
}) => {
  const paginationRange = useMemo(() => {
  }, [totalCount, pageSize, siblingCount, currentPage]);
  return paginationRange;
};

As a first step, we’ll use totalCount and pageSize to calculate the total number of pages:

const totalPageCount = Math.ceil(totalCount / pageSize);

Next, we’ll create a custom range function that accepts a start and end value and produces an array of entries from start to finish:

const range = (start, end) => {
  let length = end - start + 1;
  return Array.from({ length }, (_, idx) => idx + start);
};

My usePagination page will look like this

import React, { useMemo } from 'react';

export const DOTS = '...';

const range = (start, end) => {
    let length = end - start + 1;
    return Array.from({ length }, (_, idx) => idx + start);
};

export const usePagination = ({ totalCount, pageSize, siblingCount = 1, currentPage }) => {

    const paginationRange = useMemo(() => {
        const totalPageCount = Math.ceil(totalCount / pageSize);

        const totalPageNumbers = siblingCount + 5;
        if (totalPageNumbers >= totalPageCount) {
            return range(1, totalPageCount);
        }

        const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
        const rightSiblingIndex = Math.min(
            currentPage + siblingCount,
            totalPageCount
        );

        const shouldShowLeftDots = leftSiblingIndex > 2;
        const shouldShowRightDots = rightSiblingIndex < totalPageCount - 2;

        const firstPageIndex = 1;
        const lastPageIndex = totalPageCount;

        if (!shouldShowLeftDots && shouldShowRightDots) {
            let leftItemCount = 3 + 2 * siblingCount;
            let leftRange = range(1, leftItemCount);

            return [...leftRange, DOTS, totalPageCount];
        }

        if (shouldShowLeftDots && !shouldShowRightDots) {
            let rightItemCount = 3 + 2 * siblingCount;
            let rightRange = range(
                totalPageCount - rightItemCount + 1,
                totalPageCount
            );
            return [firstPageIndex, DOTS, ...rightRange];
        }

        if (shouldShowLeftDots && shouldShowRightDots) {
            let middleRange = range(leftSiblingIndex, rightSiblingIndex);
            return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex];
        }
    }, [totalCount, pageSize, siblingCount, currentPage]);

    return paginationRange;
};

How to Implement the Pagination Component

let’s create a file called Pagination.js in our project.

import React from 'react';
import classnames from 'classnames';
import { usePagination, DOTS } from './usePagination';
import './pagination.scss';

const Pagination = props => {
    const { onPageChange, totalCount, siblingCount = 1, currentPage, pageSize, className } = props;

    const paginationRange = usePagination({ currentPage, totalCount, siblingCount, pageSize });

    if (currentPage === 0 || paginationRange.length < 2) {
        return null;
    }

    const onNext = () => {
        onPageChange(currentPage + 1);
    };

    const onPrevious = () => {
        onPageChange(currentPage - 1);
    };

    let lastPage = paginationRange[paginationRange.length - 1];
    return (
        <ul className={classnames('pagination-container', { [className]: className })}>
            <li className={classnames('pagination-item', { disabled: currentPage === 1 })} onClick={onPrevious}>
                <div className="arrow left" />
            </li>
            {paginationRange.map(pageNumber => {
                if (pageNumber === DOTS) {
                    return <li className="pagination-item dots">&#8230;</li>;
                }

                return (
                    <li className={classnames('pagination-item', { selected: pageNumber === currentPage })} onClick={() => onPageChange(pageNumber)}>
                        {pageNumber}
                    </li>
                );
            })}
            <li className={classnames('pagination-item', { disabled: currentPage === lastPage })} onClick={onNext}>
                <div className="arrow right" />
            </li>
        </ul>
    );
};

export default Pagination;

How to Use the Custom Pagination Component

import React, { useState, useMemo } from 'react';
import Pagination from './Pagination';
import data from './examples/data/mock-data.json';

let PageSize = 10;

export default function App() {
  const [currentPage, setCurrentPage] = useState(1);

  const currentTableData = useMemo(() => {
    const firstPageIndex = (currentPage - 1) * PageSize;
    const lastPageIndex = firstPageIndex + PageSize;
    return data.slice(firstPageIndex, lastPageIndex);
  }, [currentPage]);

  return (
    <>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>FIRST NAME</th>
            <th>LAST NAME</th>
            <th>EMAIL</th>
            <th>PHONE</th>
          </tr>
        </thead>
        <tbody>
          {currentTableData.map(item => {
            return (
              <tr>
                <td>{item.id}</td>
                <td>{item.first_name}</td>
                <td>{item.last_name}</td>
                <td>{item.email}</td>
                <td>{item.phone}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
      <Pagination
        className="pagination-bar"
        currentPage={currentPage}
        totalCount={data.length}
        pageSize={PageSize}
        onPageChange={page => setCurrentPage(page)}
      />
    </>
  );
}

Output:

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories