gatsby-starter-blog にページネーションを導入する

このブログは gatsby-starter-blog をベースに作成しています *1 が、記事が増えることを想定し、トップの記事一覧ページにページネーションを導入してみました。
*1: 2022 年 10 月、nextjs をベースとしたブログに移行しました。
ページネーションは、gatsby-awesome-pagination というプラグインを使うことで簡単に実装できます。
インストール
gatsby-awesome-pagination プラグインをインストールします。
$ npm install gatsby-awesome-pagination
テンプレ化
記事一覧ページの URL は src/pages/index.js の配置から '/' となっていますが、今後はページ毎に異なる URL を動的に決定する必要があります。URL を動的に決定する例として、各記事ページはすでに src/template/blog-post.js をテンプレート化することで実現できているので、これと同様に index.js をテンプレート化すれば良さそうです。
そこで、src/pages/index.js を src/template 配下に移動します。
$ mv src/pages/index.js src/template/index.js
この index.js を、 blog-post.js と同様に gatsby-node.js の中でページ生成する処理を追加していきます。
ページを生成する
gatsby-node.js を編集します。
import { paginate } from 'gatsby-awesome-pagination';
exports.createPages = async ({ graphql, actions }) => {
const result = await graphql(
`
{
allContentfulPost() {
edges {
node {
// 取得したい要素
}
}
}
}
`
)
const posts = result.data.allContentfulPost.edges
paginate({
createPage,
items: posts,
itemsPerPage: 10,
component: path.resolve('src/templates/index.js'),
pathPrefix: ({ pageNumber }) => (
pageNumber === 0 ? '/' : '/page'
)
})
...
}
gatsby-awesome-pagination を import して paginate を使えるようにします。paginate の中では createPage を含め、以下のようなパラメータを設定します。
items
: ページ内で表示する記事の配列。ここでは GraphQL で取得した配列を指定します。itemsPerPage
: 1 ページあたりに表示する記事の数。ここでは 10 とします。component
: テンプレートのファイル。ここでは index.js を指定します。pathPrefix
: 各ページのパスを指定します。トップページは '/' 、2 ページ目以降は '/page/2', '/page/3' となるようにしています。
これにより、テンプレートとして指定した index.js で以下のような Context が自動的に利用できるようになります。
パラメータ | 説明 |
---|---|
pageNumber | ページ番号 (0 始まり) |
humanPageNumber | ページ番号 (1 始まり) |
skip | スキップする記事の数。GraphQL で $skip で利用できます |
limit | ページ内の記事の最大数。GraphQL で $limit で利用できます |
numberOfPages | ページ数 |
previousPagePath | 前のページのパス |
nextPagePath | 次のページのパス |
GraphQL の編集
上記の $skip と $limit を利用して、src/template/index.js における GraphQL のクエリを修正します。
export const pageQuery = graphql`
query($skip: Int!, $limit: Int!) {
allContentfulPost(skip: $skip, limit: $limit) {
edges {
node {
...
この時点で、ページが作成されて各ページに動的な URL が紐づいている状態となります。ブラウザで /
(1 ページ目) , /page/2
(2 ページ目) のパスにアクセスすると各ページが表示されていることが確認できるかと思います。
前後のページのリンクを付ける
前のページ、次のページに遷移できるように各ページ内にリンクを設置します。
const BlogIndex = ({ data, location, pageContext }) => {
return (
...
<ul>
<li>
{pageContext.previousPagePath && (
<Link to={pageContext.previousPagePath} rel="prev">
← Newer
</Link>
)}
</li>
<li>
{pageContext.nextPagePath && (
<Link to={pageContext.nextPagePath} rel="next">
Older →
</Link>
)}
</li>
</ul>
)
props として pageContext が受け取れるようになっています。この Context の中で、前のページのパス previousPagePath
と 次のページのパス nextPagePath
が取得できるので、これを使えばリンクが簡単に作れます。
ちなみに、最初のページの previousPagePath
と 最後のページの nextPagePath
は undefined となるので、そのときはリンクを表示しないようにします。
あとは適当に style を設定します。
<ul
style={{
display: `flex`,
flexWrap: `wrap`,
justifyContent: `space-between`,
listStyle: `none`,
padding: 0,
}}
>
こんな感じでリンクが追加できました。