Published on

Server side Pagination using contenful and Nextjs

Authors
  • avatar
    Name
    Ebimene Agent
    Twitter

    Software Engineer

Prerequisites:

Before we dive into the implementation, ensure you have the following:

  1. A Next.js project set up.
  2. A Contentful account with a space and content model(this was shown in this article Building a Next.js Blog with Contentful Integration.

Step 1: Set Up Your Next.js Project:

npx create-next-app my-pagination-app
cd my-pagination-app

Step 2: Install Dependencies:

Install the necessary packages for Contentful and server-side pagination:

npm install contentful 

Step 3: Configure Contentful:

Set up a Contentful account and create a space. Define a content model for the items you want to paginate.Everything about how to create a space and getting your environment variables have been explained in this article attached:Building a Next.js Blog with Contentful Integration. Add many blogs to your space so you can implement pagination.

Step 4: Implement Server-Side Pagination:

Fetch Data Dynamically Create a utility function to fetch data from Contentful based on page and limit. Use the contentful package to interact with the Contentful API. You can create this function inside a lib folder or utils.We will be creating a file, contentful.js inside a utils folder. Add the following code to the contentful.js file

export const createContentClient = () => {
  return createClient({
    space: process.env.CONTENTFUL_SPACE_ID,
    accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
  })
}

const client = createContentClient()
export const getEntriesByType = async (
  type,
  page = 1,
  limit = 5,
) => {
  let skip = (page - 1) * limit
  const response = await client.getEntries({
    content_type: type,
    include: 2,
    limit,
    skip,
    order: ['-sys.createdAt'],
  })
  return response.items
}

The above code communicates with the contentful api endpoints to return items. We use the limit and skip values to return specific number of items and the number of items to ignore. You may need to read the contenful api docs to understand better how the skip and limit values work. We use the skip variable to return the number of items we want to ignore. We need 5 items per page(limit), so this value is defaulted to 5.We then use the page value (defaulted to 1) and limit values to control the skip value. We can get these values from the searchParams prop that is passed to a page by nextjs under the hood. The order parameter controls how you want to order your items from contentful. Hence " order: ['-sys.createdAt'] " returns the items(in our case, blogs) in the order of the date they were created.

We need three more functions that will be getting the total number of items, the blogs, and the one to get the contents of each blog.

export const getEntriesTotalNumber = async (type) => {
  const response = await client.getEntries({
    content_type: type,
  })

  return response.total
}
export const getEntryBySlug = async (slug, type) => {
  const queryOptions = {
    content_type: type,
    include: 2,
    'fields.slug[match]': slug,
  }
  const queryResult = await client.getEntries(queryOptions)
  return queryResult.items[0]
}

export const getBlogPosts = async (page, limit) => {
  const blogs = await getEntriesByType('blogPost', page, limit)
  const blogPosts = blogs.map((blog) => blog.fields)
  return blogPosts
}

We can now call these functions in the pages that we need them. Go to where you want to render your list of blogs(it could be blogs.js inside your app's folder or the home page). Add the following code to the page where you want to render the list.

import Link from "next/link";
import { getBlogPosts, getEntriesTotalNumber } from "./utils/contentful";
import styles from "./page.module.css";

export default async function Home({ searchParams }) {
  const page =
    typeof searchParams.page === "string" ? Number(searchParams.page) : 1;
  const limit =
    typeof searchParams.limit === "string" ? Number(searchParams.limit) : 5;

  const blogs = await getBlogPosts(page, limit);
  const totalBlogs = await getEntriesTotalNumber("blogPost");
  const hasPreviousPage = page > 1;
  const hasNextPage = totalBlogs > page * limit;

  return (
    <div className={styles.main}>
      <h1>Latest Blog Posts</h1>
      <ul>
        {blogs.map((blog) => (
          <div key={blog.slug} className={styles.blog}>
            <Link href={`${blog.slug}`}> {blog.title}</Link>
          </div>
        ))}
      </ul>
      <div className={styles.pageNavLinks}>
        <Link
          href={`/?page=${hasPreviousPage ? page - 1 : 1}`}
          style={!hasPreviousPage ? { pointerEvents: "none" } : {}}
        >
          Previous
        </Link>
        <Link
          href={`/?page=${hasNextPage ? page + 1 : page}`}
          style={!hasNextPage ? { pointerEvents: "none" } : {}}
        >
          Next
        </Link>
      </div>
    </div>
  );
}

You can customize the UI of your project to meet your needs. I added a very short css code to give the blogs list page a good design. Add this code to the page.module.css file that follows a default bare nextjs app.

Conclusion

By following these steps, you've successfully implemented server-side pagination in a Next.js application using Contentful. This approach ensures efficient data retrieval and provides a seamless experience for users navigating through paginated content. Feel free to customize the code further based on your specific requirements, and leverage the power of Contentful and Next.js to create high-performance web applications with dynamic pagination.