Implementing Pagination in a React Component

By Raymond M

This article will show you how to implement pagination in a react component. Pagination is one of those features you see everywhere, from e-commerce sites and dashboards to blog feeds. It's a useful tool used to display a big dataset without overwhelming the user. In this example, we will build a React app that displays user data in a table with controls to navigate between pages, display the current page number, and select how many users are shown per page.

Step By Step Guide on Implementing Pagination

When implementing pagination in React, we need to decide what we first want to keep track of. In this case it's the current page the user is on and the number of items displayed per page (users in this case). So we'll use state to keep track of this:

  const [currentPage, setCurrentPage] = useState(1)
  const [usersPerPage, setUsersPerPage] = useState(5)

Next, we need to consider how many pages there will be. To do that, we'll take the total number of users, and divide it by the users per page and round it up:

const totalPages = Math.ceil(users.length / usersPerPage)

Now that we have the pages and number of users displayed per page set up, we need to figure out which users are going to be displayed on what page. To do that we'll have to use the slice method.

  const indexOfLastUser = currentPage * usersPerPage
  const indexOfFirstUser = indexOfLastUser - usersPerPage
  const currentUsers = users.slice(indexOfFirstUser, indexOfLastUser)

Essentially what is happening is we're getting the index of the first and last user of each page. For example, if we are displaying 5 users per page on page 1, the index of the last user will be 5, and the index of the first user is 0. Using slice with those indexes will give us the first 5 users.

Then we can take those users and map them into our table:

    <tbody>
          {currentUsers.map((user) => (
            <tr key={user.id}>
              <td>{user.id}</td>
              <td>{user.name}</td>
              <td>{user.email}</td>
              <td>{user.role}</td>
            </tr>
          ))}
    </tbody>

Now, all that's left to do is implement navigation to allow users to change the page:

const handleNextPage = () => {
    if (currentPage < totalPages) {
      setCurrentPage((prev) => prev + 1)
    }
  }

  const handlePrevPage = () => {
    if (currentPage > 1) {
      setCurrentPage((prev) => prev - 1)
    }
  }

  const handleUsersPerPageChange = (e) => {
    setUsersPerPage(Number(e.target.value))
    setCurrentPage(1)
  }

Just pass those functions into your controls and now the user can navigate back and forth between pages.

Full Solution

The following is the full solution. The users array should be in this format:

const users = [
  {
    id: 1,
    name: "Alice Johnson",
    email: "alice.johnson@example.com",
    role: "Admin",
  },
  { id: 2, name: "Bob Smith", email: "bob.smith@example.com", role: "User" },
  {
    id: 3,
    name: "Charlie Brown",
    email: "charlie.brown@example.com",
    role: "Editor",
  },
]

Full code:

import React, { useState } from "react"

export default function PaginationChallenge() {
  const [currentPage, setCurrentPage] = useState(1)
  const [usersPerPage, setUsersPerPage] = useState(5)

  const totalPages = Math.ceil(users.length / usersPerPage)

  const indexOfLastUser = currentPage * usersPerPage
  const indexOfFirstUser = indexOfLastUser - usersPerPage
  const currentUsers = users.slice(indexOfFirstUser, indexOfLastUser)

  const handleNextPage = () => {
    if (currentPage < totalPages) {
      setCurrentPage((prev) => prev + 1)
    }
  }

  const handlePrevPage = () => {
    if (currentPage > 1) {
      setCurrentPage((prev) => prev - 1)
    }
  }

  const handleUsersPerPageChange = (e) => {
    setUsersPerPage(Number(e.target.value))
    setCurrentPage(1)
  }

  return (
    <div>
      <h1>Pagination Challenge</h1>

      {/* Table */}
      <table border="1" cellPadding="5" style={{ borderCollapse: "collapse" }}>
        <thead>
          <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Email</th>
            <th>Role</th>
          </tr>
        </thead>
        <tbody>
          {currentUsers.map((user) => (
            <tr key={user.id}>
              <td>{user.id}</td>
              <td>{user.name}</td>
              <td>{user.email}</td>
              <td>{user.role}</td>
            </tr>
          ))}
        </tbody>
      </table>

      {/* Controls */}
      <div style={{ marginTop: "10px" }}>
        <button onClick={handlePrevPage} disabled={currentPage === 1}>
          Previous
        </button>
        <span style={{ margin: "0 10px" }}>
          Page {currentPage} of {totalPages}
        </span>
        <button onClick={handleNextPage} disabled={currentPage === totalPages}>
          Next
        </button>
      </div>

      {/* Users per page selector */}
      <div style={{ marginTop: "10px" }}>
        <label>Users per page: </label>
        <select value={usersPerPage} onChange={handleUsersPerPageChange}>
          <option value={5}>5</option>
          <option value={10}>10</option>
          <option value={20}>20</option>
        </select>
      </div>
    </div>
  )
}