Part 75: Implementing Pagination in Next.js: A Step-by-Step Guide

[App] Pagination

[App] Pagination

When dealing with large amounts of data, pagination is a crucial feature that enhances user experience by organizing content into manageable sections. In this guide, we'll walk through implementing pagination for a Reviews page in a Next.js application, allowing users to navigate through all available reviews efficiently. Along the way, we'll also explore some useful features of Next.js.

Setting Up the Pagination UI

The first step in adding pagination is to create a simple user interface that includes controls to navigate between pages.

Step 1: Design the Pagination Interface

The goal here is to create a user interface that allows users to navigate between different pages of reviews.

  • Navigation Links: We add a div that contains links for navigating to the previous and next pages, as well as a display for the current page number.

    <div className="flex gap-2 pb-3">
      {pagination.page > 1 && (
        <Link href={`/reviews?page=${pagination.page - 1}`}>&lt; Prev</Link>
      )}
      <span>Page {pagination.page} of {pagination.pageCount}</span>
      {pagination.page < pagination.pageCount && (
        <Link href={`/reviews?page=${pagination.page + 1}`}>Next &gt;</Link>
      )}
    </div>
    • Previous Link: Displayed only if the current page (pagination.page) is greater than 1.

    • Next Link: Displayed only if the current page is less than the total number of pages (pagination.pageCount).

    • Current Page Indicator: Shows the current page number and the total number of pages.

  • Styling: The flex class is used to arrange elements in a row, gap-2 adds space between them, and pb-3 adds padding at the bottom for better visual separation.

Managing Page Navigation

Step 2: Handle URL Parameters

Next.js provides a way to handle URL parameters through the searchParams object, which includes query string parameters.

  • Extract and Parse Page Parameter: We extract the page parameter and convert it to an integer. If the parameter is invalid or missing, it defaults to 1.

    function parsePageParam(paramValue) {
      if (paramValue) {
        const page = parseInt(paramValue);
        if (isFinite(page) && page > 0) {
          return page;
        }
      }
      return 1;
    }
  • Use in Component: Within the ReviewsPage component, we determine the current page using this function:

    export default async function ReviewsPage({ searchParams }) {
      const page = parsePageParam(searchParams.page);
      const pageSize = PAGE_SIZE;
      const { reviews, pagination } = await getReviews(pageSize, page);
      // Fetch and render reviews based on the current page
    }

Fetching the Correct Reviews

Step 4: Implement Data Fetching Logic

This step involves modifying the data fetching logic to ensure the correct set of reviews is displayed for each page.

  • Modify getReviews Function: This function now accepts pageSize and page parameters. It fetches the appropriate set of reviews and returns both the reviews and pagination metadata.

    //lib/reviews.js
    export async function getReviews(pageSize, page) {
      const { data, meta } = await fetchReviews({
        fields: ['slug', 'title', 'subtitle', 'publishedAt'],
        populate: { image: { fields: ['url'] } },
        sort: ['publishedAt:desc'],
        pagination: { pageSize, page },
      });
      return {
        reviews: data.map(toReview),
        pagination: meta.pagination,
      };
    }
    • Data: Contains the actual reviews.

    • Meta: Includes pagination information such as the current page and total page count.

  • Integrate in ReviewsPage: This component fetches reviews based on the current page and renders them.

    //app/reviews/page.jsx
    export default async function ReviewsPage({ searchParams }) {
      const page = parsePageParam(searchParams.page);
      const pageSize = PAGE_SIZE;
      const { reviews, pagination } = await getReviews(pageSize, page);
      
      return (
        <>
          <Heading>Reviews</Heading>
          <div className="flex gap-2 pb-3">
            {pagination.page > 1 && (
              <Link href={`/reviews?page=${pagination.page - 1}`}>&lt; Prev</Link>
            )}
            <span>Page {pagination.page} of {pagination.pageCount}</span>
            {pagination.page < pagination.pageCount && (
              <Link href={`/reviews?page=${pagination.page + 1}`}>Next &gt;</Link>
            )}
          </div>
          {/* ... rest of your component ... */}
        </>
      );
    }

Conclusion

By implementing pagination, users can efficiently navigate through different sets of reviews. The combination of UI, URL parameter handling, and data fetching logic ensures that the correct reviews are displayed for each page. This setup also includes basic error handling, such as ensuring that invalid page numbers default to 1, and only displaying navigation links when appropriate. Future enhancements could include disabling links when on the first or last page to prevent unnecessary requests.

Last updated