utamt engineer blog

アプリケーション開発について学んだことの備忘録です。

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

gatsby-starter-blog をベースに作成したブログの記事一覧ページにページネーションを導入してみました。

ページネーションは、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,
          }}
        >

こんな感じでリンクが追加できました。