記事数が増えると一覧にペーネーションが欲しくなりますよね?
複数ページネーションを実装するためのプラグインがあるにもかかわらず自作して実装してしまいました。
プラグインに頼らず実装したい人のために、やり方をシェアします。
※ 2021年12月v4バージョンアップに伴いリライトしました。
かみーゆ/フロントエンドエンジニア
今までのGatsbyの記事と注意点
現在ここまで記載しています。
制作するまでを目標にUPしていくので順を追ったらGatsbyサイトが作れると思います。
- インストールからNetlifyデプロイまで
- ヘッダーとフッターを追加する
- 投稿テンプレにカテゴリやらメインビジュアル(アイキャッチ)追加
- ブログ記事、カテゴリ、タグ一覧の出力
- プラグインを利用して目次出力
- プラグインナシで一覧にページネーション実装(←イマココ)
- 個別ページテンプレート作成
- プラグインHelmetでSEO調整
- CSSコンポーネントでオリジナルページを作ろう!!
- 関連記事一覧出力
- タグクラウドコンポーネントを作成する
- パンくずリストを追加する
- 記事内で独自タグ(コンポーネント)を使えるようにする
Gatsbyのv4からv5へアップグレードしたのでそのやり方をメモしておきます。Netlify の Nodeバージョンの...
このシリーズはGithub・gatsby-blogに各内容ブランチごとで分けて格納しています。
今回のソースはpaginationブランチにあります。
このシリーズではテーマGatsby Starter Blogを改造
この記事は一番メジャーなテンプレート、「Gatsby Starter Blog」を改造しています。同じテーマでないと動かない可能性があります。
早速ページネーションを実装しよう!
ページネーションを実装するためには一覧を分割しページを生成します。
さらにページネーションを出力するコンポーネントを作成します。
WordPressなど、その他のCMSに慣れていると一覧を分割しページを生成するってところがちょっと不思議です。
ページネーションを実装するためにページを分割する
まずはgatsby-node.jsにページを分割するためのコードを書いていきます。
一覧ページの実装についてはこちらを参考にしてください。
/ (プロジェクトディレクトリー)
├ gatsby-node.js(ページを生成するところ)
├ src/
| └ templates/
| └ blogs.js(一覧を出力するところ)
└ components/
└ pagination.js(新規作成)
gatsby-node.jsのブログ詳細ページを生成しているコードを利用して、数量を数えます。
変数count
にページ数を格納します。
frontmatterのpagetypeがblogのみカウントします。
// ~ 省略 ~
exports.createPages = async ({ graphql, actions, reporter }) => {
// ~ 省略 ~
if (posts.length > 0) {
const blogPosts = posts.filter(post => post.frontmatter.pagetype === "blog")
// 省略
let count = blogPosts.length console.log(count)//デバッグ
// 一覧を出力するコードを追加
createPage({
path: "/blogs/",
component: blogList,
context: {},
})
// ~ 省略 ~
}
// ~ 省略 ~
}
続けて以下のコードを追記します。今回は1ページに12記事を表示します。
たとえば45記事あったら 4つのページに分割される、といった形になります。
- /blogs/
- /blogs/page/2/
- /blogs/page/3/
- /blogs/page/4/
どこからどこまでの記事を出力するか、テンプレートblog-list.js側に値を渡します。
limit
… ループ数skip
… オフセット(どこからループを始めるか)数current
… 現在何番目page
… トータルのページ数
const postsPerPage = 12 //1ページに表示する記事の最大数
// 一覧を出力するコードを追加
let count = blogPosts.length //記事の長さ
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, //1ページに表示される最大記事数
skip: index * postsPerPage, //追加
current: pageNumber, //追加
page: numPages, //追加
},
})
}
ページが出力されたか、カンタンに調べる方法があります。
404ページにアクセスすると、出力されているページ一覧が確認できます。
blog-list.jsで値を受け取る
次にblog-list.js側で値を受け取ります。
query blosQyery()
に$limit: Int!
と$skip: Int!
を追加します。
Int!
は型が数字で空の値はダメですよーって意味です。空でもいい場合は!
を省きます。
Int!
が原因でエラーを吐いている場合は、gatyby-node.js側で間違ったコードを書いている可能性があるのでよく確かめてみましょう。
// ~ 省略 ~
// pageContextを追加
const BlogList = ({ pageContext, data, location }) => {// ~ 省略 ~
}
export default blogs
export const pageQuery = graphql`
# $limit、$skip追加
query ($limit: Int!, $skip: Int!) { site {
siteMetadata {
title
}
}
allMarkdownRemark(
# $limit、$skip追加
limit: $limit skip: $skip sort: { fields: [frontmatter___date], order: DESC }
filter: { frontmatter: { pagetype: { eq: "blog" } } }
) {
# 記事総数取得
totalCount
nodes {
# 省略
}
}
}
`
1ページに表示する記事の数は$limit
、オフセット値は$skip
に格納されるので、受け取った値をallMarkdownRemark()
で絞り込みます。
allMarkdownRemark(
limit: $limit
skip: $skip
...
)
createPageから投げられた値は引数pageContext
に格納されるので、それを利用します。
const blogs = ({ pageContext, data, location }) => {
}
ページネーションを出力するコンポーネントを作る
最初と最後、前と次へ移動する簡易的なページネーションの実装の仕方をご紹介します。
/ (プロジェクトディレクトリー)
└ components/
└ pagination.js(新規作成)
pagination.jsを作成し、次のコードを記述します。
import { Link } from "gatsby"
import React from "react"
import styled from "styled-components" //追加
const Pagination = ({ num, current, type }) => {
let first
let prev
let next
let last
if (current === 1) {
first = (
<li className="not-work" key="pagination0">
<span>最新</span>
</li>
)
} else {
first = (
<li key="pagination0">
<Link to={`/blogs/${type}${type ? "/" : ""}`}>最新</Link>
</li>
)
}
if (current === 1) {
prev = (
<li className="not-work" key="pagination1">
<span>次へ</span>
</li>
)
} else if (current === 2) {
prev = (
<li key="pagination1">
<Link to={`/blogs/${type}${type ? "/" : ""}`}>次へ</Link>
</li>
)
} else {
prev = (
<li key="pagination1">
<Link to={`/blogs/${type}${type ? "/" : ""}page/${current - 1}/`}>
次へ
</Link>
</li>
)
}
if (current === num) {
next = (
<li className="not-work" key="pagination3">
<span>前へ</span>
</li>
)
} else if (current === "") {
next = (
<li key="pagination3">
<Link to={`/blogs/${type}${type ? "/" : ""}page/2/`}>前へ</Link>
</li>
)
} else {
next = (
<li key="pagination3">
<Link to={`/blogs/${type}${type ? "/" : ""}page/${current + 1}/`}>
前へ
</Link>
</li>
)
}
if (current === num) {
last = (
<li className="not-work" key="paginatio4">
<span>最後</span>
</li>
)
} else {
last = (
<li key="pagination4">
<Link to={`/blogs/${type}${type ? "/" : ""}page/${num}/`}>最後</Link>
</li>
)
}
console.log(num)
if (num > 1) {
return (
<PaginationWrapper>
<ul>
{first}
{prev}
<li key="pagination2">
page {current}/{num}
</li>
{next}
{last}
</ul>
</PaginationWrapper>
)
} else {
return ""
}
}
export default Pagination
const PaginationWrapper = styled.nav`
ul {
display: flex;
list-style: none;
justify-content: center;
li {
padding: 0 10px;
&.not-work span {
background: rgb(41, 46, 114);
color: #fff;
opacity: 0.5;
}
span,
a {
text-decoration: none;
display: flex;
align-items: center;
font-weight: 700;
color: rgb(41, 46, 114);
border-radius: 8px;
border: 1px solid rgb(41, 46, 114);
padding: 0 10px;
}
}
}
`
あとは表示したいところにコードを追記してください。
// ~ 省略 ~
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={cateSlug} />
カテゴリやタグもページネーションを実装したい方はGitHubのpaginationブランチのコードを参考にしてください。
もっと複雑なページネーションを実装したい方へ
記事数が多くなるとより詳細なページネーションが欲しいですよね。
詳細なページネーションのソースはGitHubにあげています。
めちゃくちゃコードが長くなったのでこの記事ではコードは紹介しません。
こちらを参考にしてください。
なぜプラグインナシで実装したのか?
今回プラグインナシで実装した理由です。
Gatsbyはプラグインが豊富でいくらでもプラグインで実装できます。プラグインがうまく動かず、やむなく勉強にもなるし自力で実装することにしました。
後々よくコードを見てみたら私の書き方が間違っていただけでした。
はじめて触るGatsbyに疲れていたのもありますが、人間が一番バグります。
実装が面倒な人はgatsby-awesome-paginationあたりが人気なので、プラグインを利用するといいかもしません。
まとめ
ページネーションが実装され、安心してたくさん記事が書けるようになりました。
次の記事は「個別ページテンプレート作成」です。
皆さんのコーディングライフの一助となれば幸いです。
最後までお読みいただきありがとうございました。