GatsbyJSで表示範囲指定ありのペジネーションを作成する方法

技術


概要

GatsbyJSで現在のページを含めて指定のページ数を表示するペジネーションの作り方です。

1ページ目と最終ページは常に表示されるようにしています。

ペジネーション部分のソースコード

ペジネーションはコンポーネント化しています。

pagination.tsx
import * as React from 'react'
import { Link } from 'gatsby'

interface PaginationProps {
  numPages: number
  currentPage: number
  pathBase?: string
}

const Pagination = ({ numPages, currentPage, pathBase }: PaginationProps) => {
  const isFirst = currentPage === 1
  const isLast = currentPage === numPages
  const pageLimit = 3
  const omitFirst = currentPage - 1 > pageLimit
  const omitLast = numPages - currentPage > pageLimit
  const prevPage =
    currentPage - 1 === 1 ? pathBase : pathBase + (currentPage - 1).toString()
  const nextPage = pathBase + (currentPage + 1).toString()

  const prevText = '前へ'
  const nextText = '次へ'
  const paginationTag =
    numPages !== 1 ? (
      <nav className="pagination">
        <div>
          {!isFirst ? (
            <Link to={prevPage} rel="prev">
              {prevText}
            </Link>
          ) : (
            <span>{prevText}</span>
          )}
        </div>

        <div>
          <ul>
            {
              /*FirstPage*/
              !isFirst && (
                <div>
                  <li className="number--firstlast">
                    <Link to={pathBase}>1</Link>
                    {omitFirst && <span></span>}
                  </li>
                </div>
              )
            }
            {Array.from({ length: numPages }, (_, i) =>
              i + 1 === currentPage ? (
                <li
                  key={`pagination-number${i + 1}`}
                  className="number--current"
                >
                  <span>{i + 1}</span>
                </li>
              ) : (
                i > 0 &&
                i < numPages - 1 &&
                currentPage - pageLimit < i + 1 &&
                i + 1 < currentPage + pageLimit && (
                  <li
                    key={`pagination-number${i + 1}`}
                    className="number--link"
                  >
                    <Link to={pathBase + (i === 0 ? '' : i + 1)}>{i + 1}</Link>
                  </li>
                )
              )
            )}
            {
              /*LastPage*/
              !isLast && (
                <li className="number--firstlast">
                  {omitLast && <span></span>}
                  <Link to={pathBase + numPages}>{numPages}</Link>
                </li>
              )
            }
          </ul>
        </div>

        <div>
          {!isLast ? (
            <Link to={nextPage} rel="next">
              {nextText}
            </Link>
          ) : (
            <span>{nextText}</span>
          )}
        </div>
      </nav>
    ) : null

  return paginationTag
}

export default Pagination

const pageLimit = 3の部分の数字を変えると表示する範囲を変えられます。

使い方

gatsby-node.js に下記のようにコンテキストを持たせます。

gatsby-node.js
  // Contentful Post List
  const cflPostsPerPage = 5
  const cflNumPages = Math.ceil(cflPosts.length / cflPostsPerPage)

  Array.from({ length: cflNumPages }).forEach((_, i) => {
    createPage({
      path: i === 0 ? `/` : `/${i + 1}`,
      component: blogPostListTemplate,
      context: {        limit: cflPostsPerPage,        skip: i * cflPostsPerPage,        numPages: cflNumPages,        currentPage: i + 1,      },    })
  })

記事一覧など、ペジネーションを呼び出したい箇所で、作成したペジネーションコンポーネントを呼び出します。

import * as React from 'react'
import { graphql, Link } from 'gatsby'

//Component
import Layout from '../components/layout'
import Pagination from '../components/pagination'

const _ = require('lodash')

interface BlogListType {
  pageContext: {
    currentPage: number
    numPages: number
  }
  data: TempblogListQuery
}

const BlogList = ({ pageContext, data }: BlogListType) => {
  const posts = data.cfPosts.edges
  const { currentPage, numPages } = pageContext
・
・
・
  return (
    <Layout>
・
・
・
      <Pagination numPages={numPages} currentPage={currentPage} pathBase="/" />
    </Layout>
  )
}

export default BlogList
・
・
・

ペジネーションのスタイル指定はお好みでどうぞ。