Nextjs static blog with pagination - using Prismic

Hi Everyone (@kris, @lee, @sjcgct, @sandys ),

Sorry about the delay. I've got an example for you now, based off of a previous post for Nuxt I made.

So what you need to do is make 2 extra queries in your post, being that you're using Next.js this won't slow your project down.

For the first query for your 'next' article will be to get all results on the post type, then limit the result size to 1, then you set the query option 'after' to get the only the next document.

The idea is that then you reverse order to get your 'previous' article. You do this using the orderings option.

Here's what you're 2 queries should look like:

const prevpost = (await client.query(Prismic.Predicates.at('document.type', 'post'), { pageSize : 1 , after : `${post.id}`, orderings: '[my.post.date desc]'})).results[0] || 'undefined'

const nextpost = (await client.query(Prismic.Predicates.at('document.type', 'post'), { pageSize : 1 , after : `${post.id}`, orderings: '[my.post.date]'})).results[0] || 'undefined'

You'll then return the results to the template and pass them through the link resolver and use the Next-link component like so:

{prevpost !== 'undefined'
  ? (
    <NextLink as={linkResolver(prevpost)} href={hrefResolver(prevpost)}>
      <a>Previous Post</a>
    </NextLink>
  )
: null}
{nextpost !== 'undefined'
  ? (
    <NextLink as={linkResolver(nextpost)} href={hrefResolver(nextpost)}>
      <a>Next Post</a>
    </NextLink>
  )
: null}

You can see it's best to do a check to remove the link if there are no articles to link.

Here is my full example based on our sample Next.js blog:

import React from "react";
import Head from "next/head";
import Prismic from '@prismicio/client'
import { default as NextLink } from 'next/link'
import { RichText } from "prismic-reactjs";

import { queryRepeatableDocuments } from 'utils/queries'

// Project components
import DefaultLayout from "layouts";
import { BackButton, SliceZone } from "components/post";

// Project functions & styles
import { Client } from "utils/prismicHelpers";
import { postStyles } from "styles";
import { hrefResolver, linkResolver } from 'prismic-configuration'

/**
 * Post page component
 */
const Post = ({ post, prevpost, nextpost }) => {
  if (post && post.data) {
    const hasTitle = RichText.asText(post.data.title).length !== 0;
    const title = hasTitle ? RichText.asText(post.data.title) : "Untitled";

    return (
      <DefaultLayout>
        <Head>
          <title>{title}</title>
        </Head>
        <div className="main">
          <div className="outer-container">
            <BackButton />
            <h1>{title}</h1>
          </div>
          <SliceZone sliceZone={post.data.body} />
          {prevpost !== 'undefined'
            ? (
              <NextLink as={linkResolver(prevpost)} href={hrefResolver(prevpost)}>
                <a>Previous Post</a>
              </NextLink>
            )
          : null}
          {nextpost !== 'undefined'
            ? (
              <NextLink as={linkResolver(nextpost)} href={hrefResolver(nextpost)}>
                <a>Next Post</a>
              </NextLink>
            )
          : null}
        </div>
        <style jsx global>
          {postStyles}
        </style>
      </DefaultLayout>
    );
  }

  return null;
};

export async function getStaticProps({ params, preview = null, previewData = {} }) {
  const { ref } = previewData
  const client = Client()
  const post = await client.getByUID("post", params.uid, ref ? { ref } : null) || {}
  const prevpost = (await client.query(Prismic.Predicates.at('document.type', 'post'), { pageSize : 1 , after : `${post.id}`, orderings: '[my.post.date desc]'})).results[0] || 'undefined'
  const nextpost = (await client.query(Prismic.Predicates.at('document.type', 'post'), { pageSize : 1 , after : `${post.id}`, orderings: '[my.post.date]'})).results[0] || 'undefined'
  return {
    props: {
      preview,
      post,
      prevpost,
      nextpost
    }
  }
}

export async function getStaticPaths() {
  const documents = await queryRepeatableDocuments((doc) => doc.type === 'post')
  return {
    paths: documents.map(doc => `/blog/${doc.uid}`),
    fallback: true,
  }
}

export default Post;

I'll add this to our documentation and create an example in Slice Machine/

Let me know if you have any questions.

Thanks.

1 Like