Skip to content

Instantly share code, notes, and snippets.

@jongan69
Last active November 10, 2023 07:10
Show Gist options
  • Save jongan69/706d033f0e9b92189bd1ca521b23e067 to your computer and use it in GitHub Desktop.
Save jongan69/706d033f0e9b92189bd1ca521b23e067 to your computer and use it in GitHub Desktop.
usePagination Hook

React usePagination Hook

This hook returns a pagination range based on the current page, total number of items, and page size.

Usage

Import the usePagination hook in your React component as follows:

import { usePagination } from './usePagination';

Then, you can use the hook in your component as follows:

const paginationRange = usePagination({
  totalCount: 100, // total number of items
  pageSize: 10, // number of items per page
  siblingCount: 1, // number of siblings to show on either side of the current page
  currentPage: 5, // current page
});

Implementation Details

The usePagination hook uses the useMemo hook to memoize the pagination range based on the dependencies passed to it. The function takes an object with the following properties:

totalCount - total number of items

pageSize - number of items per page

siblingCount - number of siblings to show on either side of the current page (default value is 1)

currentPage - current page

The pagination range is calculated based on the total number of pages, the current page, and the number of siblings to show on either side of the current page. If the number of pages is less than or equal to the number of pages to be displayed, then all the pages are displayed. Otherwise, the pagination range is calculated based on the current page and the number of siblings to show on either side of it. Dots are added to indicate gaps in the pagination range.

The DOTS constant is defined as ..., and the range function is defined as a utility function to create a range of numbers between start and end inclusive.

Parameters

The usePagination hook takes an object with the following parameters:

totalCount - total number of items

pageSize - number of items per page

siblingCount - number of siblings to show on either side of the current page (default value is 1)

currentPage - current page

import { 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);
// Pages count is determined as siblingCount + firstPage + lastPage + currentPage + 2*DOTS
const totalPageNumbers = siblingCount + 5;
/*
If the number of pages is less than the page numbers we want to show in our
paginationComponent, we return the range [1..totalPageCount]
*/
if (totalPageNumbers >= totalPageCount) {
return range(1, totalPageCount);
}
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
const rightSiblingIndex = Math.min(
currentPage + siblingCount,
totalPageCount
);
/*
We do not want to show dots if there is only one position left
after/before the left/right page count as that would lead to a change if our Pagination
component size which we do not want
*/
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;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment