Pagination in Javascript and React, with a custom usePagination() hook

This article will teach you how to understand pagination in javascript and react and how to use it in React. The principles cover in this tutorial may be use for any javascript project.

What is Pagination?

Pagination is a collection of pages with the same content. It is crucial to remember that we will still refer to pagination when the material on a part of a page is split into separate pages.

When it comes to distributing items on the website in a controlled manner. So we can say that pagination makes life easier for consumers. Consider an eCommerce site with a catalog that includes hundreds of goods from various categories all on one page. Will this cause the user to get perplex? Definitely. So, how does pagination work in web development?

example-pagination

Concept behind or background of Pagination?

Let’s assume you have six things on a page and only want to show three of them at a time (per page). This implies we’ll need a total of two pages, and if we want to show two things on each page, we’ll need a total of?? Yes, you guessed correctly! Three pages are require.

This formula is straightforward:

totalPages = totalContent / contentPerPage

Implementing it in Javascript (.slice() method)

It’s simple to calculate the material per page, but how can we present different stuff depending on which page we’re on? We just need to comprehend the link between our content’s page and index. Let’s start with the .slice() Array function.

The slice() function creates a new array object with a shallow copy of a part of an array from start to end (end not included). Where start and end indicate the index of elements in that array. There will be no changes to the original array.

For example: suppose we have an array named softhunt and we want to choose only a piece of it depending on its index.

const softhunt = ["levi", "hange", "erwin", "petra", "oruo", "miche"]
scouts.slice(2, 5)
// output: [ 'erwin', 'petra', 'oruo' ]
scouts.slice(1, 3)
// output: [ 'hange', 'erwin' ]

We all know that javascript uses a zero-based index. Thus the first argument is the index from which we want to start the slice. And the second parameter is the index directly after that. For example, in the first example, we use .slice(2, 5) to get 2 to 4.

Mapping page number to index

All we need to know is the page number to determine what the startIndex and lastIndex should be. This is a straightforward connection.

// assuming we are on page one
const page = 1;
const contentPerPage = 3
const lastIndex = page * contentPerPage // 3
const firstIndex = lastIndex - contentPerPage // 0

scouts.slice(firstIndex, lastIndex)
// scouts.slice(0, 3) => [ 'levi', 'hange', 'erwin' ]

// page 2
// scouts.slice(3, 6) => [ 'petra', 'oruo', 'miche' ]

Wow!, that was simple

Custom usePagination hook

Now that we’ve understood the concept, let’s put it into action in React and construct a custom hook to assist us in automating this process. This hook accepts an object with the values contentPerPage, which specifies how many things should be display at once, and count, which specifies the total number of items (Array length). It also returns an object with the properties shown below.

  • page – current page we are on
  • totalPages – total number of pages generated
  • firstContentIndex – first index for the .slice() method
  • lastContentIndex – last index for the .slice() method
  • nextPage – function to navigate one page foward
  • prevPage – function to navigate one page backward
  • setPage – function to go to a certain page
interface UsePaginationProps {
    contentPerPage: number,
    count: number,
}

interface UsePaginationReturn {
    page: number;
    totalPages: number;
    firstContentIndex: number;
    lastContentIndex: number;
    nextPage: () => void;
    prevPage: () => void;
    setPage: (page: number) => void;
}

type UsePagination = (UsePaginationProps) => (UsePaginationReturn);

Create a folder named hooks in your React project and a file called usePagination, which will house our own hook.

Within it, type the following:

import { useState } from "react";

const usePagination: UsePagination = ({ contentPerPage, count }) => {
  const [page, setPage] = useState(1);
  // number of pages in total (total items / content on each page)
  const pageCount = Math.ceil(count / contentPerPage);
  // index of last item of current page
  const lastContentIndex = page * contentPerPage;
  // index of first item of current page
  const firstContentIndex = lastContentIndex - contentPerPage;

  // change page based on direction either front or back
  const changePage = (direction: boolean) => {
    setPage((state) => {
      // move forward
      if (direction) {
        // if page is the last page, do nothing
        if (state === pageCount) {
          return state;
        }
        return state + 1;
        // go back
      } else {
        // if page is the first page, do nothing
        if (state === 1) {
          return state;
        }
        return state - 1;
      }
    });
  };

  const setPageSAFE = (num: number) => {
    // if number is greater than number of pages, set to last page
    if (num > pageCount) {
      setPage(pageCount);
      // if number is less than 1, set page to first page
    } else if (num < 1) {
      setPage(1);
    } else {
      setPage(num);
    }
  };

  return {
    totalPages: pageCount,
    nextPage: () => changePage(true),
    prevPage: () => changePage(false),
    setPage: setPageSAFE,
    firstContentIndex,
    lastContentIndex,
    page,
  };
};

export default usePagination;

We’re using useState to manage the current page’s value; note that pageCount is also equal to the value of the previous page. I’ve tried to make the code above as clear as possible.

Implementation

We only need to import the hook and then fill in the required attributes.

...
  const {
    firstContentIndex,
    lastContentIndex,
    nextPage,
    prevPage,
    page,
    setPage,
    totalPages,
  } = usePagination({
    contentPerPage: 3,
    count: people.length,
  });
...

The firstContentIndex and lastContentIndex are then use to slice our data.

...
<div className="items">
  {people
    .slice(firstContentIndex, lastContentIndex)
    .map((el: any) => (
      <div className="item" key={el.uid}></div>
   ))}
</div>
...

Below is a basic method to help us in creating our buttons, after which we add their onClick handlers.

<div className="pagination">
  <p className="text">
    {page}/{totalPages}
  </p>
  <button onClick={prevPage} className="page">
    &larr;
  </button>
  
  {[...Array(totalPages).keys()].map((el) => (
    <button
      onClick={() => setPage(el + 1)}
      key={el}
      className={`page ${page === el + 1 ? "active" : ""}`}
    >
      {el + 1}
    </button>
  ))}
  <button onClick={nextPage} className="page">
    &rarr;
  </button>
</div>

We’ve completed our task! As you can see in the screenshot below, our usePagination hook works as expected.

react1
1st page
react2
3rd page

Thank you for taking the time to read this; I hope you enjoyed it. Please leave any questions, additions, or deletions in the comments section below or you can email us at [email protected]. or contact us through our website.

If you want to get more knowledge of react then please visit react official documentation.

Leave a Comment