GatsbyJS + Contentfulなブログでページネーションを実装する

2020年の5月に、このブログをGatsbyJS + Contentful + Netlifyという構成に移行しました。移行しながら気づいた点、苦戦した点をすこしずつ纏めて行きたいと思います。今回は、GatsbyJS + Contentfulで、ブログ記事のページネーションを実装する方法について書いてみます。

gatsby-awesome-paginationプラグイン

Gatsbyでページネーションを実現するためのプラグインに、gatsby-awesome-paginationがあります。今回はこれを使いました。

インストール

npm install --save gatsby-awesome-pagination

でインストールします。

gatsby-node.jsの実装

GatbyJSが提供するGatsby Node APIとgatsby-awesome-paginationプラグインとを使って、ページ生成時にページネーション機能を持ったページを生成するよう、gatsby-node.jsを実装します。

だいたい、次のようなコードになりました。

const path = require("path")
const { paginate } = require("gatsby-awesome-pagination")

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  
  // Contentfulから記事を公開日時降順で取得する
  const result = await graphql(`
    {
      allContentfulPost(sort: { fields: [publishedAt], order: DESC }) {
        edges {
          node {
            // 取得したいフィールドを列挙
          }
        }
      }
    }
  `)
  
  const posts = result.data.allContentfulPost.edges
  
  // 記事リストページ生成
  const template = path.resolve(`src/templates/index.js`)
  paginate({
    createPage,
    items: posts,
    component: template,
    pathPrefix: ({ pageNumber } => (pageNumber === 0 ? "/", "/pages"),
  })
}

上のコードでは、gatsby-awesome-paginationのpaginate関数を使用して、ページネーション機能のあるページを生成しています。この関数にはcomponentとして、ページのテンプレートを指定する必要があり、それをsrc/templates/index.jsとして実装しました。

テンプレート

paginate関数にcomponentとして指定するテンプレートは、

  • ページングの際に実行するページQueryをexportする
  • ページング用のリンクを含んだReactのコンポーネントをexportする

の2つが必要になります。(前者に気づかず苦戦しました...)

だいたい、次のような実装をしました。

// importやら、styled-componentsの定義は省略しています。

export const pageQuery = graphql`
  query($skip: Int!, $limit: Int!) {
    allContentfulPost(
      sort: { fields: [publishedAt], order: DESC }
      skip: $skip
      limit: $limit
    ) {
      edges {
        node {
          // 必要なフィールドを列挙
        }
      }
    }
  }
`

const IndexPage = ({ data, pageContext }) => {
  const posts = data.allContentfulPost.edges
  const Posts = posts.map(({ node }) => (
    <Post
      key={node.title}
      title={node.title}
      // ... 必要なPropertyを渡す
    />
  ))
  return (
    <Layout>
      <Container>
        {Posts}
        <Pager pageContext={pageContext} />
      </Container>
    </Layout>
  )
}

export default IndexPage

上記のコードのPostは、記事一覧での記事を表現するコンポーネント、Pagerはページング用のコンポーネントです。Pagerコンポーネントに渡しているpageContextには、

  • previousPagePath
  • nextPagePath
  • pageNumber
  • numberOfPages

といった、ページングに必要な値が含まれているので、これらを使ってページング用のコンポーネントを実装しました。

まとめ

GatsbyJS + Contentfulでページネーションを実現する方法について書いてみました。まとめると、

  • gatsby-awesome-paginationを使う
  • gatsby-node.jsでページネーションに対応したページ生成処理を実装する
  • ページネーションに対応したテンプレートを実装する
  • テンプレートでページQueryをexportする

という流れになりました。最後のページQueryがわかりにくい点でしょうか。

参考サイト