Recently while making an application in React, I had to use pagination in one of my lists. So, I decided to keep it simple and came up with an idea of a custom hook.
The custom hook will return a function, to which we can then pass the page number and it will return the first index and last index of the list along with the total number of pages.
Usage:
const [pageNumber, setPageNumber] = useState(1);
const paginator = usePagination(list.length, pageSize);
//pageSize is the number of items we want to display per page.
const [firstIndex, lastIndex, totalPages] = paginator(pageNumber);
Then we can use this information to slice up our list and implement pagination, we can store the page number in our state and update state based on user interaction.
Now, let's jump into the code that works behind this. The code is fairly simple. In the following snippet, numberOfRecords
is the total number of items that the list has, and recordsPerPage
is the count of items we want to show per page.
export const usePagination = (numberOfRecords, recordsPerPage) => {
...
}
Now we calculate the following:
-
noOfWholePages
(Number of pages containing items equals torecordsPerPage
) -
isLastPagePartial
(This boolean variable tells if the last page is filled or has less items thanrecordsPerPage
) -
noOfRecordsInLastPage
(This stores how many items are there in the last page. This will be 0 ifisLastPagePartial
is false) -
noOfPages
(The total number of pages)
const noOfWholePages = Math.trunc(numberOfRecords / recordsPerPage);
const isLastPagePartial = numberOfRecords % recordsPerPage > 0;
const noOfRecordsInLastPage = numberOfRecords % recordsPerPage;
const noOfPages = noOfWholePages + (isLastPagePartial ? 1 : 0);
Now, we need the paginator function to return from the hook. We will use the concept of javascript closures here. So, nothing can be changed in the function other than pageNumber.
const recordsBuilder = (pageNumber) => {
const firstIndex = (pageNumber - 1) * recordsPerPage;
let lastIndex = firstIndex + recordsPerPage - 1;
if (noOfPages === pageNumber) {
// Last page
if (isLastPagePartial) lastIndex = firstIndex + noOfRecordsInLastPage - 1;
}
return [firstIndex, lastIndex, noOfPages];
};
Finally, we return this function from the hook.
return recordsBuilder;
Now let's have a look at the complete code here.
export const usePagination = (numberOfRecords, recordsPerPage) => {
const noOfWholePages = Math.trunc(numberOfRecords / recordsPerPage);
const isLastPagePartial = numberOfRecords % recordsPerPage > 0;
const noOfRecordsInLastPage = numberOfRecords % recordsPerPage;
const noOfPages = noOfWholePages + (isLastPagePartial ? 1 : 0);
const recordsBuilder = (pageNumber) => {
const firstIndex = (pageNumber - 1) * recordsPerPage;
let lastIndex = firstIndex + recordsPerPage - 1;
if (noOfPages === pageNumber) {
// Last page
if (isLastPagePartial) lastIndex = firstIndex + noOfRecordsInLastPage - 1;
}
return [firstIndex, lastIndex, noOfPages];
};
return recordsBuilder;
};
I hope this post is helpful. Thank you and stay safe.
Top comments (2)
Yes correct, but I called it a hook, because I have planned to modify it to handle the page number as well, so it will have some internal state.
Still right now, I agree that it can be a simple function as well.
And the ternary operation. I completely missed it man๐ . Thanks for the catch.
Thanks for the suggestion. Thanks for giving the time to correct me ๐.