How to create a simple pagination in Next.js
- Author: Md. Saad
- Published at: September 25, 2024
- Updated at: September 25, 2024
Introduction
Next.js is a popular open-source web development framework built on top of React and designed for building server-rendered React applications. Vercel developed it and has become widely adopted for its ability to streamline the development of highly performant, production-grade web applications. This article will discuss creating the Next js app, fetching data, and finally implementing a simple pagination in the project.
Prepare Your Next.js Application
Before setting up the GitHub Actions workflow, the first and foremost step is to create a Next.js App. Use the following command to create a next.js app.
npx create-next-app@latest app-name
As it is not an article on creating the next.js app, we will not discuss it in detail. If you want to read it in detail follow the link.
Create Posts Components
After Creating a Next js app, Let’s create components. We will create two components. One is for posts and another is for pagination. Let’s create a Posts component first.
- Create a components folder at the root of the project.
- Now create a Posts.jsx. Inside it add the following codes.
"use client";
import React from "react";
import {useState} from "react";
import Pagination from "./Pagination";
export default function Posts({postData}) {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 9;
const totalPage = Math.ceil(postData.length / itemsPerPage);
const paginateData = () => {
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
return postData.slice(startIndex, endIndex);
};
const currentPageData = paginateData();
const goToNextPage = () => {
setCurrentPage((prevPage) => prevPage + 1);
};
const goToPreviousPage = () => {
setCurrentPage((prevPage) => prevPage - 1);
};
const paginateFunction = {
totalPage,
currentPage,
setCurrentPage,
goToNextPage,
goToPreviousPage,
};
return (
<>
<h1 className="text-4xl font-bold"> List of Sample Blog </h1>
<ul className="grid grid-cols-3 gap-5">
{currentPageData.map((post) => (
<li
key={post.id}
className="mb-5 bg-gray-600 p-10"
>
<h2 className="text-cyan-600 font-semibold mb-2 text-xl ">{post.title}</h2>
<p>{post.content}</p>
</li>
))}
</ul>
<Pagination paginateFunction={paginateFunction} />
</>
);
}
In this example, The Posts component accepts a prop postData, which contains an array of blog posts. It uses pagination to display a specific number of posts per page, along with navigation to move between pages. Let’s analyze the codes:
- currentPage: Holds the current page number. Initially set to 1. We have used React useState hook to manage the currentPage number.
- itemsPerPage: It is set to 9 (it can be any), indicating how many items will be displayed on each page.
- totalPage: The total number of pages, calculated by dividing the length of the postData by itemsPerPage.
- paginateData: This function slices the postData array to get the posts that should be displayed on the current page. It calculates the start and end indices based on the current page and the number of items per page.
- currentPageData: Stores the posts to be shown on the current page by calling the paginateData() function.
- goToNextPage and goToPreviousPage: Functions to move to the next or previous page by updating the currentPage state.
- paginateFunction : The paginateFunction object bundles the pagination-related functions and data (totalPage, currentPage, setCurrentPage, goToNextPage, goToPreviousPage) which will be passed as a prop to the Pagination component.
So far, we have discussed the variable. Let’s discuss what the code is rendering:
- The component renders the blog posts as a list (<ul>), with each post displayed in a grid layout.
- Each post is displayed in a styled <li> element, showing its title and content.
- After the list of posts, the Pagination component is rendered and receives the paginateFunction object as a prop to handle page navigation. For handling the page navigation a Pagination component is imported at the top though we have not created any yet. Let’s create the Pagination components now.
Create Pagination Components
- Like before, Go to the components folder.
- Now create a Paginations.jsx. Inside it add the following codes.
const Pagination = ({paginateFunction}) => {
const {totalPage, currentPage, setCurrentPage, goToNextPage, goToPreviousPage} = paginateFunction;
return (
<div className="container">
<ul className="flex items-center justify-center gap-2">
<li className="group">
<button
onClick={() => {
goToPreviousPage();
}}
className={`group flex items-center justify-center rounded-full border border-borderColor text-sm font-medium duration-300 dark:border-borderColor-dark p-2.5 ${
currentPage === 1 ? "disabled:opacity-7 cursor-not-allowed" : "cursor-pointer hover:bg-primary"
}`}
disabled={currentPage === 1}
>
Previous
</button>
</li>
{Array.from({length: totalPage}, (_, index) => (
<li
className={`group ${index + 1 === currentPage && "page-active"}`}
key={index}
>
<button
href=""
className="flex h-10 w-10 items-center justify-center rounded-full text-sm font-medium duration-300 hover:bg-cyan-600 hover:text-white group-[.page-active]:bg-cyan-600 dark:group-[.page-active]:text-white"
onClick={() => setCurrentPage(index + 1)}
>
{index + 1}
</button>
</li>
))}
<li className="group">
<button
onClick={() => {
goToNextPage();
}}
className={`group flex items-center justify-center rounded-full border border-borderColor text-sm font-medium duration-300 dark:border-borderColor-dark p-2.5 ${
currentPage === totalPage ? "disabled:opacity-7 cursor-not-allowed" : "cursor-pointer hover:bg-primary"
}`}
disabled={currentPage === totalPage}
>
Next
</button>
</li>
</ul>
</div>
);
};
export default Pagination;
In this example, these codes are designed to display pagination controls (e.g., page numbers, "Previous" and "Next" buttons) for navigating through multiple pages of content. Here's a breakdown of how the component works:
- The Pagination component receives a single prop, paginateFunction, which contains several pagination-related functions and data:
- totalPage: Total number of pages.
- currentPage: The current active page.
- setCurrentPage: Function to change the current page.
- goToNextPage: Function to go to the next page.
- goToPreviousPage: Function to go to the previous page.
- Previous Button: Creates a button to navigate to the previous page. If the currentPage is the first page (1), it disables the button. Otherwise, it is enabled and will call the goToPreviousPage function when clicked.
- Page Numbers: The page numbers are dynamically generated using Array.from based on the totalPage value. Each page number is rendered as a button inside a list item (<li>). Clicking on a page number calls the setCurrentPage function to update the current page.
- Next Button: Similar to the "Previous" button, but it navigates to the next page. If the currentPage is the last page (totalPage), the button is disabled. Otherwise, it is enabled and will call the goToNextPage function when clicked.
Thus the Pagination component is ready to use for pagination. Finally, we need to fetch the data and show them.
Fetching Data
Now it is time to fetch data and show them on our site.
- Go to app/page.js file.
- Remove all the codes. Add the following codes:
import Posts from "@/components/Posts";
export default async function Home() {
let data = await fetch("https://api.vercel.app/blog");
let posts = await data.json();
return (
<div className="container mx-auto grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<Posts postData={posts} />
</main>
</div>
);
}
In this Example:
- The Home component fetches the blog post data from an API endpoint asynchronously, ensuring the data is available before rendering.
- The fetch() function is used to retrieve data from an API endpoint: "https://api.vercel.app/blog".
- await ensures that the code waits for the response to be fetched before proceeding.
- The response is stored in data and is converted to JSON using the json() method, storing the result in the posts variable.
- Finally, the Posts component is imported which will handle the rendering of the individual blog posts. The fetched posts data is passed to the Posts component via the postData prop, which handles the actual display of each blog post.
All of that is there for us to view on the webpage. Run npm run dev, and execute the code. Each page can be accessed by using pagination.
Conclusion
Adding pagination to your Next.js app enhances the user experience by efficiently handling large data sets, whether fetched from an API or a database. You can implement pagination on a Next js app. Thus, we can ensure seamless navigation between data pages, improving the overall usability of your application.
I hope that this article provides you with some valuable information. Please do not hesitate to contact StaticMania with any questions or feedback. Happy coding!