How to Paginate in React

·8 min read

How to Paginate in React

Need for Pagination

Every web application is made up of some kind of data. The data can vary in number. When the data is smaller in number, it could be handled easily. But the problem arises when the data is huge and today’s web applications are expected to manage such huge data efficiently. 

One major issue is how to display the data on the front end. Suppose, the client-side is receiving one thousand records and these records are to be displayed one by one on the frontend. Is it efficient to display all the one thousand records at once? Absolutely not. Not only will this turn the UI ugly, but also, it will negatively affect the user experience. Here, enter the concept of Pagination. 

 

What is Pagination?

Pagination is a technique using the data that is fetched from the server in a form of groups. Such groups are created according to a particular value and each group has that number of records. 

For example, instead of fetching all the one thousand records at once, ten records will be fetched at a time. So these ten records are displayed on the screen. To navigate to the next ten records, the user will have buttons. In simple words, the frontend will display buttons to navigate to different pages and each page will display ten records. 

 

React pagination

Pagination can be performed in several ways in React. One way is to create custom React Pagination. But creating custom React Pagination is tough and time-consuming. Another way is to use pre-defined Pagination components such as Material-UI’s Pagination component. But these predefined components do not provide much flexibility. The third option is using the react-paginate package with the React hooks. 

In this tutorial, we will use the react-paginate package along with React hooks to create React pagination. 

Let’s begin creating a React project using the following command. 

npx create-react-app pagination

 

Next, create a file named data.js in the src folder and add the following data to it. 

const data = [

  { name: "Sherlocke", department: "Research and Development", city: "Bandar Pusat Jengka"},

  { name: "Shantee", department: "Product Management", city: "Luoshe" },

  { name: "Reta", department: "Legal", city: "Cabedelo" },

  { name: "Coralie", department: "Product Management", city: "Bella Vista" },

  { name: "Tatiania", department: "Services", city: "Okayama-shi" },

  { name: "Micah", department: "Legal", city: "Xialaba" },

  { name: "Stafani", department: "Business Development", city: "Nagasaki-shi" },

  { name: "Garrot", department: "Accounting", city: "Umabay" },

  { name: "Roobbie", department: "Product Management", city: "Junzhuang" },

  { name: "Andeee", department: "Legal", city: "Loakulu" },

  { name: "Avrit", department: "Training", city: "Xinglong" },

  { name: "Napoleon", department: "Accounting", city: "Terentang" },

  { name: "Elliott", department: "Legal", city: "Końskowola" },

  { name: "Anna-diana", department: "Research and Development", city: "Laban" },

  { name: "Clint", department: "Human Resources", city: "Ardazubre" },

  { name: "Jasmine", department: "Support", city: "Lunéville" },

  { name: "Flin", department: "Training", city: "Daxinshao" },

  { name: "Katuscha", department: "Accounting", city: "Ciwaru" },

  { name: "Florinda", department: "Legal", city: "Sheksna" },

  { name: "Francklin", department: "Sales", city: "Sumberjati" },

  { name: "Merissa", department: "Services", city: "Haarlem" },

  { name: "Daryle", department: "Engineering", city: "Pul-e Sangī" },

  { name: "Rona", department: "Services", city: "Borne Sulinowo" },

  { name: "Daniela", department: "Business Development", city: "Charneca" },

  { name: "Finn", department: "Engineering", city: "Takehara" },

  { name: "Tova", department: "Human Resources", city: "Kalugmanan" },

  { name: "Audre", department: "Research and Development", city: "Alor Setar" },

  { name: "Hedvige", department: "Business Development", city: "Żabieniec" },

  { name: "Olivia", department: "Business Development", city: "Qianchuan" },

  { name: "Opal", department: "Marketing", city: "Dumaguete" },

  { name: "Percival", department: "Support", city: "Esfarāyen" },

  { name: "Tove", department: "Accounting", city: "Filimonovo" },

  { name: "Diannne", department: "Training", city: "Laslovo" },

  { name: "Teddy", department: "Product Management", city: "Mercedes" },

  { name: "Skipton", department: "Human Resources", city: "Pryamitsyno" },

  { name: "Wren", department: "Business Development", city: "Santo Ângelo" },

  { name: "Teirtza", department: "Services", city: "Komendantsky aerodrom" },

  { name: "Eloise", department: "Research and Development", city: "Eguia" },

  { name: "Sapphira", department: "Engineering", city: "Cadiz" },

  { name: "Darci", department: "Marketing", city: "Dzel" },

  { name: "Luella", department: "Research and Development", city: "Butuan" },

  { name: "Concettina", department: "Services", city: "Ipoh" },

  { name: "Nels", department: "Product Management", city: "Yushugou" },

  { name: "Gram", department: "Accounting", city: "Alistráti" },

  { name: "Austine", department: "Human Resources", city: "Kombandaru" },

  { name: "Teriann", department: "Marketing", city: "Longxi" },

  { name: "Dino", department: "Engineering", city: "Episkopí" },

  { name: "Bengt", department: "Marketing", city: "Pinaring" },

  { name: "Sofia", department: "Marketing", city: "Parthenay" },

  { name: "Coral", department: "Training", city: "Unden" },

];

export default data;

The data array has a total of fifty objects, each having three key-value pairs. This mock data will be used in the React application for pagination. 

 

Install the react-paginate package using the following command. 

npm install react-paginate

 

First of all, we need a state that will hold the page number. 

const [page, setPage] = useState(0);

The initial value of page is 0, meaning, on the initial rendering, the very first page will be displayed on the screen. 

 

Next, import the data from the data.js file and store it in a state. 

const [employees, setEmployees] = useState(data);

 

As mentioned earlier, pagination means to divide data in the form of a group. In simple words, the number of records to be displayed per page should be fixed. In our case, the total number of records is fifty and each page will hold five records. Thus, the total number of pages will be ten.

const employeesPerPage = 5;

 

We also need to track the number of pages visited by the user. 

const numberOfRecordsVistited = page * employeesPerPage;

 

So, when the user is on page 3, the value of page is 2, thus 2 * 5 = 10, meaning, 10 records are visited. But why is numberOfRecordsVisitied required? Because we need to extract the correct records from the employees. By using numberOfRecordsVisited, we can find out which 5 records are required. 

Suppose, the user clicked on the third button, then we need the records from the 10th and 15th positions. How do we know the records should be between 10th and 15th positions? With the help of numberOfRecordsVisited.

Observe the following.

employees

.slice(numberOfEmployeesVistited, numberOfEmployeesVistited + employeesPerPage)

In the above code, employees is being sliced using numberOfEmployeesVisited. When the user clicks on the third button, the value of numberOfEmployeesVisited is 10. So numberOfEmployeesVisited added to employeesPerPage is 15 (10+15). The slice method will extract the records between the 10th and 15th positions and these values will be rendered on the screen.

Now, we have the records according to the page the user is visiting. Observe the following code. 

const displayEmployees = employees
  .slice(
    numberOfEmployeesVistited,
    numberOfEmployeesVistited + employeesPerPage
  )
  .map((employee) => {
    return (
      <div className="card">
        <h4>Name: {employee.name}</h4>
        <h4>Department: {employee.department}</h4>
        <h4>City: {employee.city}</h4>
      </div>
    );
  });

In the above code, the employees that is being sliced using numberOfEmployeesVisited, is being mapped into the displayEmployees. This will be used to render the records on the UI. 

Moreover, the following CSS is used to make the pages look a little better. 

.card {
  width: 40%;
  height: auto;
  background-color: bisque;
  margin: auto;
  border: 2px solid black;
}

 

Let’s add displayEmployees to the return statement. 

return <div className="App">{displayEmployees}</div>;

 

As of now, this is how App.js looks. 

import "./App.css";
import { useState } from "react";
import data from "./data";
 
function App() {
  const [page, setPage] = useState(0);
  const [employees, setEmployees] = useState(data);
 
  const employeesPerPage = 5;
  const numberOfEmployeesVistited = page * employeesPerPage;
  console.log(numberOfEmployeesVistited);
  const displayEmployees = employees
    .slice(
      numberOfEmployeesVistited,
      numberOfEmployeesVistited + employeesPerPage
    )
    .map((employee) => {
      return (
        <div className="card">
          <h4>Name: {employee.name}</h4>
          <h4>Department: {employee.department}</h4>
          <h4>City: {employee.city}</h4>
        </div>
      );
    });
 
  return <div className="App">{displayEmployees}</div>;
}
 
export default App;

Let’s check the UI. 

React UI Components for Pagination

The first five records are being displayed on the screen but there are no buttons for navigation of course. For that, we need react-paginate

First, import ReactPaginate from “react-paginate”.

import ReactPaginate from "react-paginate";

 

The ReactPaginate component will handle everything itself from buttons to navigation. But we have to provide values for several props. Let’s understand these props one by one. 

<ReactPaginate

  previousLabel={"Previous"}

  nextLabel={"Next"}

/>

previousLabel and “nextLabel” should have string values because these strings will be labeled on the extreme ends of the navigation for the user to navigate to the previous and next pages. 

 

The next props is pageCount. The value of pageCount should be equal to the total number of records. In our case, this value should be ten but it can change over time. So let’s create a variable to calculate the total number of records. 

const totalPages = Math.ceil(employees.length / employeesPerPage);

 

The ceil function of the Math module is used to round off the values, thus avoiding unwanted bugs.

<ReactPaginate
  previousLabel={"Previous"}
  nextLabel={"Next"}
  pageCount={totalPages}
/>;

 

The next props and the most important one is onPageChange. Its value should be a function and this function will decide what happens when the user navigates from one page to another. Observe the following function. 

const changePage = ({ selected }) => {
  setPage(selected);
};

The value of selected is equal to the page the user wants to navigate to. (If the user clicked on 3, the values of selected will be 2 because the counting starts from 0). 

 

The page state initialized earlier has to be updated to the value the user wants to navigate to. 

<ReactPaginate
  previousLabel={"Previous"}
  nextLabel={"Next"}
  pageCount={totalPages}
  onPageChange={changePage}
/>;

 

The remaining five props will define the CSS for all the buttons. 

<ReactPaginate
  previousLabel={"Previous"}
  nextLabel={"Next"}
  pageCount={totalPages}
  onPageChange={changePage}
  containerClassName={"navigationButtons"}
  previousLinkClassName={"previousButton"}
  nextLinkClassName={"nextButton"}
  disabledClassName={"navigationDisabled"}
  activeClassName={"navigationActive"}
/>;
  • containerClassName: for the navigation buttons
  • previousLinkClassName: for the previous button on the extreme left
  • nextLinkClassName: for the next button on the extreme right
  • disabledClassName: for the buttons that will be disabled
  • activeClassName: for the buttons that will be active

 

Following is the CSS. 

 
.navigationButtons {
  width: 80%;
  height: 40px;
  list-style: none;
  display: flex;
  justify-content: center;
  margin: auto;
  padding-top: 40px;
}
 
.navigationButtons a {
  padding: 10px;
  margin: 8px;
  border-radius: 5px;
  border: 1px solid red;
  color: red;
  cursor: pointer;
}
 
.navigationButtons a:hover {
  color: white;
  background-color: red;
}
 
.navigationActive a {
  color: white;
  background-color: red;
}
 
.navigationDisabled a {
  color: grey;
  background-color: grey;
}

Let’s check the UI. 

React UI components with pagination component

On the first rendering, the first five records are displayed on the screen. On the navigation, the first page is active. Let’s try to navigate. 

 

React UI pagination components

As the second button is clicked, the next five records are rendered on the UI. When the seventh button is clicked, the records are rendered on the UI accordingly, thanks to the slice function and numberOfEmployeesVisited

 

Wrapping it up

Creating a working React Pagination is a bit complicated because of the confusing calculations. It would be more complicated and challenging if the custom pagination is done. The react-paginate packages make it a lot easier to create React Pagination with some calculations and CSS.

In this tutorial, we discussed what pagination is and how to create a working React Pagination using the react-paginate package.