Front End Programming
  1. ホーム
  2. ブログ一覧
  3. Gatsbyブログサイト移行物語5~プラグインナシで一覧にページネーション実装~

Gatsbyブログサイト移行物語5~プラグインナシで一覧にページネーション実装~

JavaScriptReactGatsby

記事数が増えると一覧にペーネーションが欲しくなりますよね?

複数ページネーションを実装するためのプラグインがあるにもかかわらず自作して実装してしまいました。

プラグインに頼らず実装したい人のために、やり方をシェアします。

この記事を書いた人

かみーゆ/フロントエンドエンジニア

セブ島在住の気ままなフリーランスエンジニア。テクニカルディレクター・エンジニア講師・ブリッジSEを経て今に至る。CMS concrete5エバンジェリスト。テックブログ以外も「磨耗しない人生の選択」や「海外生活」のライフスタイルについて発信。好きなものは肉とビール。

Read More

今までのGatsbyの記事と注意点

現在ここまで記載しています。
制作するまでを目標にUPしていくので順を追ったらGatsbyサイトが作れると思います。

  1. インストールからNetlifyデプロイまで
  2. 投稿ページの充実と画像の方法
  3. ブログ記事、カテゴリー、タグ一覧の出力
  4. プラグインを利用して目次出力
  5. プラグインナシで一覧にページネーション実装(←イマココ)
  6. 個別ページテンプレート作成
  7. プラグインHelmetでSEO調整
  8. CSSコンポーネントでオリジナルページを作ろう!!
  9. 関連記事一覧出力

このシリーズではテーマGatsby Starter Blogを改造

この記事は一番メジャーなテンプレート、「Gatsby Starter Blog」を改造しています。同じテーマでないと動かない可能性があります。

早速ページネーションを実装しよう!

ページネーションを実装するためには一覧を分割しページを生成します。
さらにページネーションを出力するコンポーネントを作成します。

WordPressなど、その他のCMSに慣れていると一覧を分割しページを生成するってところがちょっと不思議です。

ページネーションを実装するためにページを分割する

まずはgatsby-node.jsにページを分割するためのコードを書いていきます。

一覧ページの実装の仕方についてはこちらを参考にしてください。

実用性重視!使えるボタンのCSSコード・スニペット集!
Gatsbyブログサイト移行物語3~ブログ記事、カテゴリー、タグ一覧の出力~

gatsbyのブログ用記事を抽出し一覧を作りました。カテゴリー、タグ一覧もぞれぞれ用意したのでだいぶ使い勝手がよ・・・

/ (プロジェクトディレクトリー)
    ├ gatsby-node.js(ページを生成するところ)
    ├ src/
    |    ├ templates/
    |    |   └ blogs.js(一覧を出力するところ)
    └ components/
         └ pagination.js(新規作成)


gatsby-node.jsのブログ詳細ページを生成しているコードを利用して、数量を数えます。
変数countにページ数を格納します。

frontmatterのpagetypeがblogのみカウントします。

// ~ 省略 ~

exports.createPages = async ({ graphql, actions, reporter }) => {
  // ~ 省略 ~

  let count = 0 //追加

  if (posts.length > 0) {
  //ブログ詳細ページを生成しているコード
    posts.forEach((post, index) => {
    if (post.frontmatter.pagetype === 'blog') {
        const previousPostId = index === 0 ? null : posts[index - 1].id
        const nextPostId = index === posts.length - 1 ? null : posts[index + 1].id

        createPage({
          path: post.fields.slug,
          component: blogPost,
          context: {
            id: post.id,
            previousPostId,
            nextPostId,
            hero: post.frontmatter.hero,
          },
        })
        count++ //追加
      }
	})

  // ~ 省略 ~

  }

  // ~ 省略 ~

}


続けて以下のコードを追記します。今回は1ページに12記事を表示します。

contextに値を追加します。

limitはループ数、skipはオフセット(どこからループを始めるか)数です。

currentには現在どのページを表示しているか値を格納し、pageにはトータルのページ数を格納します。

これで一覧ページのテンプレートpages.jsに各値を渡せます。

  // ~ 省略 ~
  count++
})

// ここから
const postsPerPage = 12 //追加
let numPages = Math.ceil(count / postsPerPage) //追加

for (let index = 0; index < numPages; index++) {
  const withPrefix = pageNumber => pageNumber === 1 ? `/blogs/` : `/blogs/page/${pageNumber}/`//追加
  const pageNumber = index + 1//追加

  createPage({
    path: withPrefix(pageNumber), //修正
    component: blogList,
    context: {
      limit: postsPerPage, //追加
      skip: index * postsPerPage, //追加
      current: pageNumber, //追加
      page: numPages, //追加
    }
  })
}


こんなまどろっこしいコードを書かなくても、構造によってはposts.lengthで記事数を取得できます。

私の場合mdファイルの出力をループするもの(一覧出力)とそうでないもので分けています。なので、タイプ分けする必要のない人はlet count = 0count++も必要ありません。

let count = 0をこちらのコードに差し替えてください。

const count = posts.length

pages.jsで値を受け取る

次にpages.js側で値を受け取ります。

query blosQyery()$limit: Int!$skip: Int!を追加します。

Int!は型が数字で空の値はダメですよーって意味です。空でもいい場合は!を省きます。

Int!が原因でエラーを吐いている場合は、gatyby-node.js側で間違ったコードを書いている可能性があるのでよく確かめてみましょう。

import React from "react"

// ~ 省略 ~

const blogs = ({ pageContext, data, location }) => { //なければpageContextを追加
  // ~ 省略 ~
})

export default blogs

export const pageQuery = graphql`
  query blosQyery(
    $limit: Int!
      $skip: Int!
    ) {
    site {
      siteMetadata {
        title
      }
    }
    allMarkdownRemark(
      limit: $limit
      skip: $skip
      sort: {fields: [frontmatter___date], order: DESC }
      filter: {frontmatter: {pagetype: { eq: "blog" } } }
    )
    {

    totalCount
      nodes {
        excerpt
        fields {
          slug
        }
        frontmatter {
        title
        date(formatString: "YYYY.MM.DD")
        description
        category
        cateId
        hero
        tags
        }
      }
    }
  }
`


1ページに表示する記事の数は$limit、オフセット値は$skipに格納されるので、受け取った値をallMarkdownRemark()で絞り込みます。

allMarkdownRemark(
  limit: $limit
  skip: $skip
  sort: {fields: [frontmatter___date], order: DESC }
  filter: {frontmatter: {pagetype: { eq: "blog" } } }
)


createPageから投げられた値は引数pageContextに格納されます。

const blogs = ({ pageContext, data, location }) => {
}

ページネーションを出力するコンポーネントを作る

前と次へ移動する簡易的なページネーションの実装の仕方をご紹介します。

ページネーション

src/components/にpagination.jsを作成します。

import { Link } from "gatsby"
import React from "react"

const Prev = ({ current, type }) => {
	if (current === 1) {
		return (
			<li class="pagination__prev not-work"><span>Newer</span></li>
		)
	} else if (current === 2) {
		return (
			<li class="pagination__prev"><Link to={`/blogs/${type}/`}>Newer</Link></li>
		)
	} else {
		return (
			<li class="pagination__prev"><Link to={`/blogs/${type}page/${current - 1}/`}>Newer</Link></li>
		)
	}
}

const Next = ({ num, current, type }) => {
	if (current === num) {
		return (
			<li class="pagination__next not-work"><span>Older</span></li>
		)
	} else {
		return (

			current === '' ? <li class="pagination__next"><Link to={`/blogs/${type}page/2/`}>Older</Link></li> :
				<li class="pagination__next"><Link to={`/blogs/${type}page/${current + 1}/`}>Older</Link></li>
		)
	}
}

const Pagination = ({ num, current, type }) => {
	return (
		<ul class="pagination">
			<Prev current={current} num={num} type={type} />
			page {current}/{num}
			<Next current={current} num={num} type={type} />
		</ul>
	)
}

export default Pagination


あとは表示したいところにコードを追記してください。

// ~ 省略 ~
import Pagination from "../components/blogList/pagination"
// ~ 省略 ~

const blogs = ({ pageContext, data, location }) => {
	const { current, page } = pageContext
	// ~ 省略 ~

	return (
		<Layout location={location} title="銀ねこアトリエ">
			{/* ~ 省略 ~*/}
			<Pagination num={page} current={current} type="" />
			{/* ~ 省略 ~*/}
		</Layout>
	)
})


カテゴリーやタグ一覧でもページネーションを実装したいときはtypeを追加してください。

<Pagination num={page} current={current} type={tags} />

もっと複雑なページネーションを実装したい方へ

記事数が多くなるとより詳細なページネーションが欲しいですよね。

ページネーション

詳細なページネーションのソースはGitHubにあげています。
めちゃくちゃコードが長くなったのでこの記事ではコードは紹介しません。

こちらを参考にしてください。

pagination.js | GitHub

なぜプラグインナシで実装したのか?

今回プラグインナシで実装した理由です。

Gatsbyはプラグインが豊富でいくらでもプラグインで実装できます。プラグインがうまく動かず、やむなく勉強にもなるし自力で実装することにしました。

後々よくコードを見てみたら私の書き方が間違っていただけでした。
はじめて触るGatsbyに疲れていたのもありますが、人間が一番バグります。

実装が面倒な人はgatsby-awesome-paginationあたりが人気なので、プラグインを利用するといいかもしません。

まとめ

ページネーションが実装され、安心してたくさん記事が書けるようになりました。

次回「Gatsbyブログサイト移行物語」ではprivacypolicyなど、ループに含めたくないけどmdファイルで管理したいページの実装方法をご紹介(掲載済)します!

皆さんのコーディングライフの一助となれば幸いです。

最後までお読みいただきありがとうございました。

関連記事もあわせてお読みください

Web制作に関する人気の記事

海外移住・ライフスタイルに関する人気の記事

キャリアアップ・転職に関する人気の記事