DEV Community

Cover image for Steps to Add Pagination to Your React TypeScript Project
Rinkaku
Rinkaku

Posted on

Steps to Add Pagination to Your React TypeScript Project

With the number of articles both in my portfolio and blogging platform slowly increasing, adding pagination had become increasingly necessary. For the portfolio, pagination improves the viewing comfort for visitors. On the blogging platform, pagination was essential because the layout was not designed to handle more than ten articles at once. In this article, I’ll show you how to implement pagination without requiring changes to the backend.


Create a New Pagination Component

The first step is to create a pagination component that is separate from the parent component. This separation ensures:

  • Reusability: The component can be reused in other parts of the application or even other projects.
  • Scalability: Features like a dropdown to select the number of items per page can be added later.

Here’s the code for the Pagination component:

import React from "react";

interface PaginationProps {
  currentPage: number;
  totalPages: number;
  onPageChange: (page: number) => void;
}

const Pagination: React.FC<PaginationProps> = ({ currentPage, totalPages, onPageChange }) => {
  const handleClick = (page: number) => {
    if (page > 0 && page <= totalPages) {
      onPageChange(page);
    }
  };

  return (
    <div>
      <button
        onClick={() => handleClick(currentPage - 1)}
        disabled={currentPage === 1}
      >
        Previous
      </button>
      {Array.from({ length: totalPages }, (_, index) => (
        <button
          key={index + 1}
          onClick={() => handleClick(index + 1)}
          disabled={currentPage === index + 1}
        >
          {index + 1}
        </button>
      ))}
      <button
        onClick={() => handleClick(currentPage + 1)}
        disabled={currentPage === totalPages}
      >
        Next
      </button>
    </div>
  );
};

export default Pagination;
Enter fullscreen mode Exit fullscreen mode

This component renders three types of buttons:

  1. Previous Page Button: Disabled if the user is on the first page.
  2. Page Number Buttons: Dynamically generated based on the total number of pages.
  3. Next Page Button: Disabled if the user is on the last page.

When a user clicks on any of these buttons, the onPageChange event is triggered and updates the page state in the parent component.


Modify the Parent Component

The parent component handles API calls and manages pagination states. Here are the key steps:

Create State Variables:
currentPage to track the current page.
totalPages to calculate the total number of pages based on the fetched data.

Handle Page Changes:
Update currentPage when a user interacts with the Pagination component.
Dynamically slice the fetched data to display items for the selected page.

Here’s a simplified version of the parent component:

import { useEffect, useState } from "react";
import Container from "react-bootstrap/Container";
import BlogCard from "./BlogCard";
import Pagination from "../../components/Pagination";
import axios from "axios";

interface BlogPost {
  id: number;
  title: string;
  author: string;
  thumbnail: string;
  content: string;
  publishedAt: string;
}

const apiUrl = import.meta.env.VITE_API_URL;

export default function BlogList() {
  const [blogPosts, setBlogPosts] = useState<BlogPost[]>([]);
  const [currentPage, setCurrentPage] = useState<number>(1);
  const [totalPages, setTotalPages] = useState<number>(0);
  const itemsPerPage = 10;

  useEffect(() => {
    const fetchBlogPosts = async () => {
      try {
        const response = await axios.get(`${apiUrl}/api/blog`);
        setBlogPosts(response.data);
        setTotalPages(Math.ceil(response.data.length / itemsPerPage));
      } catch (error) {
        console.error("Error fetching blog posts", error);
      }
    };
    fetchBlogPosts();
  }, []);

  const handlePageChange = (page: number) => {
    setCurrentPage(page);
  };

  const startIndex = (currentPage - 1) * itemsPerPage;
  const currentItems = blogPosts.slice(startIndex, startIndex + itemsPerPage);

  return (
    <Container>
      <h2>Welcome to the blog</h2>
      {currentItems.map((blog) => (
        <BlogCard
          key={blog.id}
          id={blog.id}
          title={blog.title}
          thumbnail={blog.thumbnail}
          excerpt={blog.content.substring(0, 60) + "..."}
        />
      ))}
      <Pagination
        currentPage={currentPage}
        totalPages={totalPages}
        onPageChange={handlePageChange}
      />
    </Container>
  );
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

With this setup, you now have a scalable and reusable pagination component. It works seamlessly with the parent component and dynamically adjusts as the number of posts increases. This approach requires no backend changes, making it ideal for projects where the backend does not support pagination out of the box.

You can further enhance the component by adding features like a dropdown to select the number of items per page or search and filter options. For now, this implementation provides a solid foundation for handling pagination in React with TypeScript.

Top comments (0)