DEV Community

sigitp
sigitp

Posted on

GatsbyJS Pagination without Plugins

Running App Example

Example of running GatsbyJS blog with pagination https://master.d2c2u44of9gyth.amplifyapp.com/. This App front-end is based on GatsbyJS/React components. The pagination done by customizing gatsby-node.js , blog-list.js, and the blog-post.js.

To me, this approach is easier to implement and at the same time, provides good coding practice.

There are two parts of the pagination:

Blog Post pagination (let's call it BPP)

Blog Post pagination displays next and previous post relatives to the post that currently being viewed. See below example:

Screen Shot 2020-05-19 at 1.38.31 PM

Blog Listing pagination (let's call it BLP)

Blog Listing pagination displays how many pages in total. Provides page listing as well as next and previous page links. See below example:

Screen Shot 2020-05-19 at 1.38.13 PM

Code

gatsby-node.js

As usual, Gatsby will generate static pages during build, we can control the pages by using createPages() method inside gatsby-node.js. Below snippet taken from https://github.com/sigitp-git/sigit.cloud-gatsby/blob/master/gatsby-node.js .

//...lines removed... // Dynamically reate pages based on graphql query on slugs from each node, put component of that page from blog-post.js template // Create pagination using src/templates/blog-list.js exports.createPages = ({ graphql, actions }) => { const { createPage } = actions const blogPostTemplate = path.resolve('./src/templates/blog-post.js') const blogListTemplate = path.resolve('./src/templates/blog-list.js') // this graphql is function string to pass graphql query, this is a node version of graphql // this query returns a promise of slugs. use then instead of async await return graphql(` query loadSlugQuery ($limit: Int!){ allMarkdownRemark( sort: { fields: [frontmatter___date], order: DESC } limit: $limit ) { edges { node { fields { slug } frontmatter { title } } } } } `, { limit: 1000}).then(result => { const posts = result.data.allMarkdownRemark.edges posts.forEach((post, index) => { // create prev and next on each posts render (for Blog Post Pagination, BPP) const previous = index === posts.length - 1 ? null : posts[index + 1].node const next = index === 0 ? null : posts[index - 1].node // previous and next are objects props sent as pageContect object to blogPostTemplate createPage({ path: post.node.fields.slug, component: blogPostTemplate, context: { slug: post.node.fields.slug, previous, next, }, }) }) // Create blog list pages (for Blog List Pagination, BLP) // Assign path /2, /3, p/4, etc const postsPerPage = 6 const numPages = Math.ceil(posts.length / postsPerPage) Array.from({ length: numPages }).forEach((_, i) => { createPage({ path: i === 0 ? `/` : `${i + 1}`, component: blogListTemplate, context: { limit: postsPerPage, skip: i * postsPerPage, numPages, currentPage: i + 1 }, }); }); }) } 
Enter fullscreen mode Exit fullscreen mode

Note that previous and next are node objects (blog post objects) passed as pageContext to blog-post.js during render. We will utilize these two objects on our blog-post.js to create links to previous and next post.

Also note that numPages , limit, skip, and currentPage are objects (blog list objects) passed as pageContext to blog-list.js during render. We will utilize these objects on our blog-list.js to create links to blog listing pages.

blog-post.js

We will use the Blog Post Pagination inside blog post page, below snippet taken from https://github.com/sigitp-git/sigit.cloud-gatsby/blob/master/src/templates/blog-post.js .

On this file, pageContext contains previous and next object passed by gatsby-node.js. We will use these objects to create links to previous and next post.

const BlogPost = ({ data, pageContext }) => { //console.log(pageContext) const { previous, next } = pageContext //...lines removed... return ( //...lines removed... <ul style={{ display: `flex`, flexWrap: `wrap`, justifyContent: `space-between`, listStyle: `none`, padding: 0, }} > <li> {previous && ( <Link to={previous.fields.slug} rel="prev"> {"<<"+previous.frontmatter.title} </Link>  )} </li>  <li> {next && ( <Link to={next.fields.slug} rel="next"> {next.frontmatter.title+">>"} </Link>  )} </li>  </ul> 
Enter fullscreen mode Exit fullscreen mode
blog-list.js

We will use the Blog List Pagination inside blog listing page, below snippet taken from https://github.com/sigitp-git/sigit.cloud-gatsby/blob/master/src/templates/blog-list.js .

On this file, pageContext contains numPages , limit, skip, and currentPage passed by gatsby-node.js. We will use these objects to create links to blog listing pages.

const BlogList = ({ data, pageContext}) => { //console.log(pageContext) const { numPages, limit, skip, currentPage } = pageContext //...lines removed... return ( //...lines removed... <div> <ul style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center', alignItems: 'center', listStyle: 'none', padding: 0, }} > {!isFirst && ( <Link to={prevPage} rel="prev" style={{marginTop: '0.1rem', marginBottom: '0.1rem', padding: '0.5rem', color: 'var(--themeColor)'}}> {"<< Prev"} </Link>  )} {Array.from({ length: numPages }, (_, i) => ( <li key={`pagination-number${i + 1}`} style={{ margin: 0, }} > <Link to={`/${i === 0 ? '' : i + 1}`} style={{ marginTop: '0.1rem', marginBottom: '0.1rem', padding: '0.5rem', textDecoration: 'none', color: i + 1 === currentPage ? '#ffffff' : 'var(--themeColor)', background: i + 1 === currentPage ? 'var(--themeColor)' : '', }} > {i + 1} </Link>  </li>  ))} {!isLast && ( <Link to={nextPage} rel="next" style={{ marginTop: '0.1rem', marginBottom: '0.1rem', padding: '0.5rem', color: 'var(--themeColor)' }}> {"Next >>"} </Link>  )} </ul>  </div> 
Enter fullscreen mode Exit fullscreen mode

Summary

GatsbyJS pagination can be done with plugins, but also can be done with simple code on gatsby-node.js , blog-list.js, and the blog-post.js.

References:

https://www.gatsbyjs.org/docs/adding-pagination/

https://nickymeuleman.netlify.app/blog/gatsby-pagination

https://github.com/NickyMeuleman/gatsby-paginated-blog

Discuss on Dev.to

Top comments (1)

Collapse
 
isaactait profile image
Isaac Tait

Great article! Helped me get on track with pagination. Much appreciated