DEV Community

Cover image for Building a Pagination Component with ReactJS
Oscar Ortiz
Oscar Ortiz

Posted on

Building a Pagination Component with ReactJS

Table of contents

Introduction

Pagination

In this guide, we will learn how to create a Pagination component to display data at a certain amount on each page. By the end of this guide, we will have a complete working pagination component. We will focus more on the Pagination component's functionality aspect and will not dive too deep into the styling. We will provide an online editor link to follow along. In today's world wide web, we see lots and lots of data displayed on the user's screen. Usually, we get this data from a database (API) where we, the developers, need to figure out a way to display that data correctly; in some cases, we will have a designer with a design ready for us to work with, which only leaves us to worry about the functionality. With the tools you'll earn in this guide, you'll be able to take this component to the next level.

We will be working with data from a public API for Amiibos. If we want to learn more about the API we are working with, feel free to check out their documentation.

What we assume you know before starting this guide

  • Basic JavaScript knowledge
  • Basic ReactJS knowledge
  • ReactJS hooks basic usage

Setup

Here is our setup project. Feel free to fork the project to start making changes.

App.jsx This is what our app will look like at the start.

import { useEffect, useState } from "react";
import axios from "axios";

export default function App() {
  // Our Data
  const [data, setData] = useState([]);

  // fetching our data
  useEffect(() => {
    axios
      .get("https://www.amiiboapi.com/api/amiibo")
      .then((res) => setData(res.data.amiibo))
      .catch((err) => console.log(err));
  }, []);

  return (
    <div>
      <h1 className=" text-2xl text-center">Pagination ReactJs</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

What we need to know

We import a few things at the start of our app.

useState - allows us to manage the state of our application/component

useEffect - allows us to make asynchronous calls within our component

Axios - an HTTP framework that allows us to request data from the browser


Creating Pagination Component

Problem

We want to create our pagination component. We will create a file called Pagination. jsx
Create a functional component. Once created, render the Pagination component into our app.

What we need to know

Have an understanding of creating React functional components and exporting and importing.

Solution

Pagination.jsx should have the following code.

import React from "react";

export default function Pagination() {
  return (
    <div>
      <p> Pagination Component </p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Import Pagination.jsx into App.jsx

import { useEffect, useState } from "react";
import axios from "axios";
import Pagination from "./Pagination";

export default function App() {
  // Our Data
  const [data, setData] = useState([]);

  // fetching our data
  useEffect(() => {
    axios
      .get("https://www.amiiboapi.com/api/amiibo")
      .then((res) => setData(res.data.amiibo))
      .catch((err) => console.log(err));
  }, []);

  return (
    <div>
      <h1 className=" text-2xl text-center">Pagination ReactJs</h1>

      <Pagination/>

    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Setting Up Pagination

Problem

The pagination component will need to take in some data to work accordingly. We need to know how much data we want to display at once, how many pages we want to show the user to navigate through, a component or components that will render out with the data, and of course, the data itself we want to pass to our pagination.

What we need to know

We need to understand how props are passed through functional components. Working with arguments will allow us to have more control over our data.

Our Pagination component will take four parameters. We are naming our parameters to match our needs.

Pagination({data, RenderComponent, pageLimit, dataLimit})

  • data: the data we passing through
  • RenderComponent: the component that will display our data
  • pageLimit: the number of pages to select from
  • dataLimit: the amount of data to display on each page

Solution

Update Pagination.jsx

export default function Pagination({data, RenderComponent, pageLimit,dataLimit}){

  return (
    <div>
      <p> Pagination Component </p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Component State

Problem

Our pagination will need to have a state of its own. We must determine how many total pages we obtain from our data. We need to track the current page we are viewing.

What we need to know

The Math module can help us round up our total. We need to know the length of our data and divide that by the amount of data we want to display per page, giving us a total amount of pages.

Solution

Starting at page one allows us to set a default value to our currentPage variable.

const [pages] = useState(Math.round(data.length / dataLimit));
const [currentPage, setCurrentPage] = useState(1);
Enter fullscreen mode Exit fullscreen mode

Updated Code

import React, { useState } from "react";

export default function Pagination({data, RenderComponent, pageLimit,dataLimit}){

  const [pages] = useState(Math.round(data.length / dataLimit));
  const [currentPage, setCurrentPage] = useState(1);

  return (
    <div>
      <p> Pagination Component </p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Update App.jsx

<Pagination data={data} pageLimit={5} dataLimit={10} RenderComponent={Amiibo} />

import { useEffect, useState } from "react";
import axios from "axios";
import Amiibo from "./Amiibo";
import Pagination from "./Pagination";

export default function App() {
  // Our Data
  const [data, setData] = useState([]);

  // fetching our data
  useEffect(() => {
    axios
      .get("https://www.amiiboapi.com/api/amiibo")
      .then((res) => setData(res.data.amiibo))
      .catch((err) => console.log(err));
  }, []);

  return (
    <div>
      <h1 className=" text-2xl text-center">Pagination ReactJs</h1>

      <Pagination
        data={data}
        pageLimit={5}
        dataLimit={10}
      />
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

If we forget what our arguments mean, check back to the pagination setup for a reminder.


Setting Up Functionality

Problem

Our pagination component needs to accomplish a few functionalities, such as going to the next page, going back to the previous page, changing to the selected page, and gathering data for the page.

What we need to know

Have an idea of how to work with functions for our functional components and how to set a new state to our variable.

Solution

Here are the functions we will be working with

  function goToNextPage() {}

  function goToPreviousPage() {}

  function changePage() {}

  const getPaginatedData = () => {}

  const getPaginationGroup = () => {}
Enter fullscreen mode Exit fullscreen mode

goToNextPage function

Problem

We need to figure out how we can go to the next page. What are some ways we can tell our component to change page values?

What we need to know

What is our current page

Solution

function goToNextPage(){
  setCurrentPage((currentPage) => currentPage+ 1);
}
Enter fullscreen mode Exit fullscreen mode

goToPreviousPage function

Problem

How can we go to the previous page? What are some ways we can tell our component to change page values?

What we need to know

What is our current page

Solution

function goToPreviousPage() {
  setCurrentPage((currentPage) => currentPage - 1);
}
Enter fullscreen mode Exit fullscreen mode

changePage function

Problem

How can we get the value of the user's click?

What we need to know

We need to know how to work with event handlers.

Solution

function changePage(event) {
  const pageNumber = Number(event.target.textContent);
  setCurrentPage(pageNumber);
 }
Enter fullscreen mode Exit fullscreen mode

getPaginatedData function

Problem

We need to get the starting and last index of the array items within the page we are viewing.

What we need to know

We need to know how to work with arrays to acquire index numbers.

Solution

const getPaginatedData = () => {
  const startIndex = (currentPage * dataLimit) - dataLimit;
  const endIndex = startIndex + dataLimit;
  return data.slice(startIndex, endIndex);
};
Enter fullscreen mode Exit fullscreen mode

getPaginationGroup function

Problem

We need to determine the total number of pages depending on two values.

What we need to know

We need to know our page limit, array fill, and map methods.

Solution

const getPaginationGroup = () => {
    let start = Math.floor((currentPage - 1) / pageLimit) * pageLimit;
    return new Array(pageLimit).fill().map((_, idx) => start + idx + 1);
};
Enter fullscreen mode Exit fullscreen mode

We are returning a new array if we pass the last index of our page nav number.


Pagination UI

Now that we have created all the functionality needed for our component, we can move on to creating elements for our UI. Since this does not require too much critical thinking, we will provide styled elements. We will need three elements: the previous button, the next button, and the navbar of numbers to allow the users to change page numbers. Last is the component we want to render for our data.

Previous Button

 <button
  onClick={goToPreviousPage}
  className={`prev ${currentPage <= 1 ? 'hidden' : ''}`}>
  prev
</button>
Enter fullscreen mode Exit fullscreen mode

Next Button

<button
  onClick={goToNextPage}
  className={`next ${currentPage >= pages ? 'hidden' : ''}`}>
  next
</button>
Enter fullscreen mode Exit fullscreen mode

Page Numbers

{getPaginationGroup().map((item, index) => (
  <button
  key={index}
  onClick={changePage}
  className={` paginationItem ${currentPage === item ? ' px-3 py-2 bg-gray-500/30 rounded-full' : null}`}
            >
    <span>{item}</span>
  </button>
))}
Enter fullscreen mode Exit fullscreen mode

Rendering Component

<div className="sm:grid sm:grid-cols-2 sm:gap-4 lg:grid-cols-3">
  {getPaginatedData().map((d, idx) => (
    <RenderComponent key={idx} data={d} />
  ))}
</div>
Enter fullscreen mode Exit fullscreen mode

RenderComponent UI

Now that our Pagination component is complete, we can finish it up by adding the child component we want to render within our pagination component. We have provided a fully styled component to make it easier for us towards the end of this guide. Feel free to style it up how ever we would like.

Amiibo.jsx Our amiibo card component is already styled up for us with Tailwind

import React from "react";

export default function Amiibo({ data }) {
  const amiibo = data.map((el) => (
    <div className="mx-auto w-full md:mx-0 md:flex md:flex-col">
      <div
        className="my-10 bg-gray-500/30 shadow-xl border-2 border-black rounded-lg p-4  mx-auto transition ease-in-out hover:scale-110 duration-300 "
        key={data.tail}
      >
        <img
          src={el.image}
          alt={el.character}
          className="mx-auto w-auto drop-shadow-2xl  max-h-56"
        />
        <p className="text-center text-2xl font-jost underline">
          {el.character}
        </p>

       <table className="mx-auto text-sm w-full text-left">
         <thead>
           <tr className="">
             <th>Country</th>
             <th>Release Date</th>
             <th>Game</th>
           </tr>
         </thead>

         <tbody className="font-semibold">
          <tr>
            <td>United States</td>
            <td>{el.release.na}</td>
            <td>{el.amiiboSeries}</td>
          </tr>

          <tr>
            <td>Japan</td>
            <td>{el.release.jp}</td>
          </tr>

          <tr>
            <td>Europe</td>
            <td>{el.release.eu}</td>
          </tr>

          <tr>
            <td>Australia</td>
            <td>{el.release.eu}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
 ));

 return <div>{amiibo}</div>;
}

Enter fullscreen mode Exit fullscreen mode

Next import our Amiibo component into our App component.

import Amiibo from './Amiibo.jsx'
Enter fullscreen mode Exit fullscreen mode

Finally

Update <Pagination /> component within App.jsx

Add <Pagination data={data} pageLimit={5} dataLimit={10} RenderComponent={Amiibo} />

Conclusion

By the end of this article, we have learned how to create and understand how a pagination component works. It is essential to understand how our code works altogether. Not only does it help us develop as developers, but it can also help us use the tools we are working with more efficiently.
These articles are mostly intended for personal use in becoming a better programmer and writer and developing my programming skills. Please drop any feedback or corrections you believe should be made to help me and others. Thank you for your time and for sticking this far!

Top comments (3)

Collapse
 
kumarkalyan profile image
Kumar Kalyan

Keep up good work . Amazing article

Collapse
 
naucode profile image
Al - Naucode

Great article, you got my follow, keep writing!

Collapse
 
cleveroscar profile image
Oscar Ortiz

Thank you for that!