Gatsby にページネーションを導入する

本サイトは gatsby-starter-default をベースに構築している。そのためページネーションのような気の利いた機能は元からついていない。そこまで多くの記事を書く見通しは経っていないが、記事一覧が延々と縦に長くなっていくのはどうにも落ち着かないので早々にページネーション機能は整えておきたかった。

ページネーションの自作

ページネーションみたいな世の中一般的な機能がプラグインとして存在しないわけはない。それは疑うまでもないことだが、チュートリアルをこなし Gatsby の拡張方法がなんとなくわかってきたこのタイミングをみすみす逃すよりはこのくらいの機能であれば自作することでより Gatsby と親密になれるだろうと思った。

何より「こうやったら実現できそう」という設計が頭の中にあったので試さずにはいられなかった。

大まかに必要な事は下記

  • ページネーションの各ページ用のレイアウトファイルを作成する。
  • gatsby-node.js でページネーションの各ページ用の URL を作成する。

ページネーション用のレイアウト

レイアウトファイルは下記のようにした。「ページネーションの数字がどのように切り替わるのか」というロジックは MaterialUI 先生に丸投げした。そのため PostsPagination コンポーネントは @material-ui/lab/PaginationPagination コンポーネントを薄くラップしてあるだけだ。PostExcerpt は記事見出しのコンポーネント。

src/layouts/pagination-layout.js
1import React from "react"
2import { graphql } from "gatsby"
3
4import GlobalLayout from "./global-layout"
5import SEO from "../components/seo"
6import PostsPagination from "../components/posts-pagination"
7import PostExcerpt from "../components/post-excerpt"
8
9export default function PaginationLayout ({ data, pageContext }) {
10 const {pageNum, lastPageNum} = pageContext
11 return (
12 <GlobalLayout>
13 <SEO title="All Posts" />
14 {data.allFile.edges.map(({node}, idx) => {
15 return (
16 <PostExcerpt
17 key={idx}
18 createdDate={node.childMdx.frontmatter.date}
19 name={node.name}
20 title={node.childMdx.frontmatter.title}
21 excerpt={node.childMdx.excerpt}
22 />
23 )
24 })}
25 <PostsPagination currentPageNum={pageNum} lastPageNum={lastPageNum} />
26 </GlobalLayout>
27 );
28}
29
30export const query = graphql`
31query PaginationLayoutQuery($maxPostsInPage: Int, $skipCount: Int) {
32 allFile(
33 filter: {sourceInstanceName: {eq: "posts"}, internal: {mediaType: {eq: "text/mdx"}}}
34 limit: $maxPostsInPage
35 skip: $skipCount
36 sort: {fields: childMdx___frontmatter___date, order: DESC}
37 ) {
38 edges {
39 node {
40 name
41 childMdx {
42 frontmatter {
43 title
44 date
45 }
46 excerpt
47 }
48 }
49 }
50 }
51}
52`

ページネーションの各ページ

レイアウトができたので、ページネーションの各ページの URL を作る。一部省略だが gatsby-node.js を下記のように編集した。こうすることで /page/1//page/2/ のような URL が Gatsby に登録される。

gatsby-node.js
1exports.createPages = async ({ graphql, actions }) => {
2 const { createPage } = actions
3 await createPaginationPages(graphql, createPage)
4}
5
6async function createPaginationPages(graphql, createPage) {
7 const result = await graphql(`
8 {
9 allMdx {
10 totalCount
11 }
12 site {
13 siteMetadata {
14 maxPostsInPage
15 }
16 }
17 }
18 `)
19 const totalPostsCount = result.data.allMdx.totalCount
20 const maxPostsInPage = result.data.site.siteMetadata.maxPostsInPage
21 const lastPageNum = Math.ceil(totalPostsCount/maxPostsInPage)
22 for (let start = 1; start <= lastPageNum; start++) {
23 const slug = `/page/${start}/`
24 createPage({
25 path: slug,
26 component: path.resolve(`./src/layouts/pagination-layout.js`),
27 context: {
28 pageNum: start,
29 maxPostsInPage: maxPostsInPage,
30 lastPageNum: lastPageNum,
31 skipCount: (start - 1) * maxPostsInPage,
32 }
33 })
34 }
35}
© 2021 K.S.K. All rights reserved., Built with Gatsby