Gatsby.js - 記事一覧ページとページネーション

1. 記事一覧ページを出力

ただ記事一覧を表示させたい場合は、記事一覧を表示させたいページに下記のように記述すると出力できます。

import React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"

export default ({ data }) => {
  const posts = data.allMarkdownRemark.edges

  return (
    <Layout>
      <h1>Blog</h1>
      {posts.map(({ node }) => (
        <article key={node.fields.slug}>
          <Link to={node.fields.slug}>
            <h2>{node.frontmatter.title}</h2>
          </Link>
        </article>
      ))}
    </Layout>
  )
}

export const pageQuery = graphql`
  query {
    allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
      edges {
        node {
          id
          fields {
            slug
          }
          frontmatter {
            title
            date(formatString: "YYYY/MM/DD")
          }
        }
      }
    }
  }
`

{posts.map(({ node }) => ( ~ ))}に挟まれている部分が繰り返し出力される部分です。

2. 記事一覧を分割してページネーションを作成する

記事分割とページネーションは、Nicky Meuleman さんが分かりやすい記事を書いてくれているので参考にして作成しています。記事一覧を分割するにはgatsby-node.jsにページ(ページ 2、ページ 3..とか)を動的に作成するために下記を記述します。ここではblog-temp.jsというファイルに記事一覧を出力させています。スラッグの部分はここでは/blog/にしていますが表示させたいページにあわせて変更します。

//gatsby-node.js

const blogTemp = path.resolve("src/templates/blog-temp.js") //パス

...

const postsPerPage = 2 //記事一覧に表示させる記事数
const numPages = Math.ceil(posts.length / postsPerPage) //記事数 ÷ 表示させる記事数

Array.from({ length: numPages }).forEach((_, i) => {
  createPage({
    path: i === 0 ? `/blog/` : `/blog/${i + 1}`, //スラッグ
    component: blogTemp,
    context: {
      skip: i * postsPerPage, //新しい記事からスキップさせる記事数
      limit: postsPerPage, //表示させる記事の制限数
      numPages,
      currentPage: i + 1,
    },
  })
})

記事一覧出力部分は上記と同じで分割したページの移動にページネーションを追加したのが下記のような記述になります。ここでのページネーションはページ数を数字で表示させるページネーションです。

//blog-temp.js

import React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"

const BlogList = ({ data, pageContext }) => {
  const posts = data.allMarkdownRemark.edges
  const { numPages } = pageContext

  return (
    <Layout>
      ....
      <ul>
        {Array.from({ length: numPages }, (_, i) => (
          <li key={`pagination-number${i + 1}`}>
            <Link to={`/blog/${i === 0 ? "" : i + 1}`}>{i + 1}</Link>
          </li>
        ))}
      </ul>
    </Layout>
  )
}
export default BlogList

export const pageQuery = graphql`
  query blogPageQuery($skip: Int!, $limit: Int!) {
    allMarkdownRemark(
      sort: { order: DESC, fields: [frontmatter___date] }
      skip: $skip
      limit: $limit
    ) {
      edges {
        node {
          id
          fields {
            slug
          }
          frontmatter {
            title
            date(formatString: "YYYY/MM/DD")
          }
        }
      }
    }
  }
`