DEV Community

Cover image for Lets make a custom hook for client side Pagination in React
Jyotirmaya Sahu
Jyotirmaya Sahu

Posted on

Lets make a custom hook for client side Pagination in React

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);
Enter fullscreen mode Exit fullscreen mode

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) => {
...
}
Enter fullscreen mode Exit fullscreen mode

Now we calculate the following:

  1. noOfWholePages (Number of pages containing items equals to recordsPerPage)
  2. isLastPagePartial (This boolean variable tells if the last page is filled or has less items than recordsPerPage)
  3. noOfRecordsInLastPage (This stores how many items are there in the last page. This will be 0 if isLastPagePartial is false)
  4. 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);
Enter fullscreen mode Exit fullscreen mode

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];
  };
Enter fullscreen mode Exit fullscreen mode

Finally, we return this function from the hook.

return recordsBuilder;
Enter fullscreen mode Exit fullscreen mode

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;
};

Enter fullscreen mode Exit fullscreen mode

I hope this post is helpful. Thank you and stay safe.

Discussion (4)

Collapse
lukeshiru profile image
LUKESHIRU

Just so you know, you can use this as a plain function, because it is (is not using any React hooks, and prepending use to the name of a function doesn't make it a hook). What I mean is that you can just call it pagination or something like that, and you can use it everywhere, not just inside function components in React. You might also take a look at Math.ceil that will simplify the logic a little, and when you have something like this: logic ? true : false, you can just write logic without the ternary.

Cheers!

Collapse
iamdoctorj profile image
Jyotirmaya Sahu Author • Edited

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.

Collapse
lukeshiru profile image
LUKESHIRU

Don't get me wrong, having this kind of logic in reusable pure functions is way better than having it in a hook. You can just have it as a function and then use it from a hook :)

Thread Thread
iamdoctorj profile image
Jyotirmaya Sahu Author

Thanks for the suggestion. Thanks for giving the time to correct me πŸ˜ƒ.