SB

How to add pagination to Gatsby site

April 13, 2021

-- views

table of contents

Adding pagination is one of those things that a good part of the application we make will have, therefore, is important to know how to add pagination to any page or component in our applications.

Today I want to make a quick tutorial on how to add pagination to a Gatsby-created website. The tutorial is made with a blog site using Sanity.io headless CMS, regardless, the process is very similar and can be applied to any other application of Gatsby.

Side note: On the Gatsby website you can find an example in which they add pagination to a blog that uses markdown. You can check it here.

Without further to do, let’s start.

1. Create a Template

Before adding pagination, we have to create a template that will be used to render all the pages created from pagination. Now, you can use a simple page instead of a template but in this example (as in Gatsby docs) we’re going to use a regular template (the process is the same, you just need to change the path to the file to be used as a template).

You can see on the code snippet below, we created a template page called blog-list-template.js. Inside this template, the most important part to adding pagination is, inside our graphql query we need to add two (2) query variables (skip and limit). These variables help us determine how many items we’ll have per page and how many items we have to skip in order to create the next page.

import React from 'react';
import { graphql } from 'gatsby';
 
const YourComponent = ({ pageContext }) => {
  return (
    // Your JSX here
  )
}
 
export const query = graphql`
  query BlogList($skip: Int!, $limit: Int!) {
    allSanityPost(
      limit: $limit
      skip: $skip
    ) {
      totalCount
      // Rest of your query here
    }
  }
`;

Note: Your template/page will automatically receive a prop called pageContext. In that prop you will see all the props you will pass from your gatsby-node function (more details in the next step).

The rest of your template can be created according to what your project needs.

2. Create a gatsby-node function

const path = require('path');
 
async function pagination({ graphql, actions }) {
    const { createPage } = actions;
    const { data } = await grapqhl(`
    {
      allSanityPost {
        totalCount
      }
    }
  `);
 
    const { totalCount } = data.allSanityPost;
    const postsPerPage = 10;
    const numPages = Math.ceil(totalCount / postsPerPage);
    Array.from({ length: numPages }).forEach((_, i) => {
        createPage({
            path: i === 0 ? `/blog` : `/blog/${i + 1}`,
            component: path.resolve('./src/templates/blog-list-template.js'),
            context: {
                limit: postsPerPage,
                skip: i * postsPerPage,
                numPages,
                currentPage: i + 1
            }
        });
    });
}

The first thing we have to get is the total amount of items in our data-collection. In my case, I’m retrieving the total amount of posts stored in my allSanityPost Collection. To do so, we can use the totalCount parameter that graphql offers us.

Note: In the query, I’m retrieving content from Sanity just because that’s the CMS I’m using but here you can apply the same query to any CMS or wherever you have your content stored. Just change the collection name to the one you need and you’re good to go.

Next, we create all the variables we need to create our pagination. We have:

Finally, we create an array using the numPages computed before as the length of the array (this is just vanilla JavaScript), and for each group of items in the array, we create a page using the createPage function provided by gatsby-node. Notice how we simply ignore the first argument of the forEach function by using the underscore, by doing this, we ignore the callback function the forEach method is expecting. The second argument is the index of the array.

To finish our pagination function we pass to the create function the required options via a JavaScript Object. We pass a path (the route of each page), a component to be used to render each page (we created ours in the first step), and finally, inside the context, we pass first the 2 variables expected from our query (limit and skip) and also the numPages and currentPage in case we need them in our template/page to render any component.

All these props are passed to our template/page via pageContext. For example, if your component needs the current-page variable you can extract it in the template/page component using props.pageContext.currentPage and then use it as any regular prop in your components.

The last thing to do is to export the createPages function and wait for all the promises to resolve. Now just restart the server and check on your newly created pages. If you used the same path as in the example that means that your first page will be on the route /blog after that the next pages will be on /blog/:index.

exports.createPages = async ({ graphql, actions }) => {
    await Promise.all([
        pagination({ graphql, actions })
        // rest of your functions
    ]);
};

Note: There are several ways to organize your gatsby-node.js functions. Here I’m just creating all my functions first and then calling them at the end of the file and awaiting all the promises.

That’s it…

That’s it! that’s all you need to add basic pagination to your website.

I hope this short tutorial helps you!

See you in the next one…