microCMS

Next.js(SSG)でページネーションを実装してみよう

かみむら

この記事は公開後、1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本記事ではNext.js(SSG)でページネーションを実装していきます。以前に書いたmicroCMS + Next.jsでJamstackブログを作ってみようの拡張版になります。本記事はこのチュートリアルを終えてる前提で話を進めていきます。

今回の作成イメージはmicroCMSブログのコンテンツ一覧の下部にあるページネーションです。

前提

下記のバージョンで開発を行っています。バージョンの差異によって若干機能が異なる可能性があります。

  • Next 13.1.1
  • react 18.2.0
  • react-dom 18.2.0


コンポーネントの作成

はじめに、ページネーションを作成するためのベースとなるコンポーネントを作成します。components/Pagination.jsを作成してください。

こちらはコードの全体像です。

//components/Pagination.js
import Link from 'next/link';

export const Pagination = ({ totalCount }) => {
  const PER_PAGE = 5;

  const range = (start, end) =>
        [...Array(end - start + 1)].map((_, i) => start + i)

  return (
    <ul>
      {range(1, Math.ceil(totalCount / PER_PAGE)).map((number, index) => (
        <li key={index}>
          <Link href={`/blog/page/${number}`}>{number}</Link>
        </li>
      ))}
    </ul>
  );
};

このコンポーネントの説明は以下になります。

rangeの引数に(start, end)を与えて、その値を元に配列を作成します。これで、totalCountが20でPER_PAGEが5とすると(20 /5)で4が返ります。これはページネーションのリスト数になります。
② rangeで作成した配列をmapして各数値を取り出します。

実際にコンポーネントのtotalCountに数値を入れると以下のようになります。

<Pagination totalCount={20} />

実装通り4つのリストを作成することができました。

一覧ページでのページネーション

上記で作成したコンポーネントを使って、一覧ページにページネーションの実装をしていきましょう。

それでは、pages/index.jsにロジックを書いていきます。一覧ページの実装はmicroCMS + Next.jsでJamstackブログを作ってみようを参考にしています。こちらはコードの全体像です。

// pages/index.js
import Link from 'next/link';
import { client } from "../libs/client";
import { Pagination } from '../components/Pagination';

export default function Home({ blog, totalCount }) {
  return (
    <div>
      <ul>
        {blog.map(blog => (
          <li key={blog.id}>
            <Link href={`/blog/${blog.id}`}>{blog.title}</Link>
          </li>
        ))}
      </ul>
      <Pagination totalCount={totalCount} />
    </div>
  );
}

export const getStaticProps = async () => {
  const data = await client.get({ endpoint: "blog", queries: { offset: 0, limit: 5 } });

  return {
    props: {
      blog: data.contents,
      totalCount: data.totalCount
    },
  };
};

ポイントはtotalCountでコンテンツの合計を取得してるところです。microCMSのリスト形式のレスポンスにはすべての合計値(totalCount)が含まれています。この値をpropsとして受け取って、Paginationに渡しています。

もう一つのポイントは、microCMSのAPIでoffsetlimitを使ってコンテンツ数を絞っています。

https://your-service.microcms.io/api/v1/blog?offset=0&limit=5

offsetは何件目から取得するかを指定します。デフォルト値は0です。
limitは取得件数を指定します。デフォルト値は10です。ここでは5件取得しています。

試しに、microCMSの記事を10件作成して検証してみましょう。上から10~6件目のコンテンツが取得できます。

個別のページネーション

次に、絞り込みを行った個別のページを作成していきます。

SSGでページネーションを作成する場合は、SSRと違って/page/1/page/2のようにして、各ページ毎にコンテンツを取得するのがベターです。それでは、pages/blog/page/[id].jsを作成してください。コードの全体像はこちらです。

// pages/blog/page/[id].js
import Link from 'next/link';
import { Pagination } from '../../../components/Pagination';
import { client } from "../../../libs/client";

const PER_PAGE = 5// pages/blog/[id].js
export default function BlogPageId({ blog, totalCount }) {
  return (
    <div>
      <ul>
        {blog.map(blog => (
          <li key={blog.id}>
            <Link href={`/blog/${blog.id}`}>{blog.title}</Link>
          </li>
        ))}
      </ul>
      <Pagination totalCount={totalCount} />
    </div>
  );
}

// 動的なページを作成
export const getStaticPaths = async () => {
  const repos = await client.get({ endpoint: "blog" });

  const range = (start, end) => [...Array(end - start + 1)].map((_, i) => start + i);

  const paths = range(1, Math.ceil(repos.totalCount / PER_PAGE)).map((repo) => `/blog/page/${repo}`);

  return { paths, fallback: false };
};

// データを取得
export const getStaticProps = async (context) => {
  const id = context.params.id;

  const data = await client.get({ endpoint: "blog", queries: { offset: (id - 1) * 5, limit: 5 } });

  return {
    props: {
      blog: data.contents,
      totalCount: data.totalCount,
    },
  };
};

少し冗長的なコードになりましたが重要なところを説明していきます。 

getStaticPathsで動的なページを作成

先程と同じで、range という関数を使って配列を作成します。PER_PAGEが5なのでtotalCountが20の場合は4つのページ(例: blog/page/1、blog/page/2...)が作成できます。

getStaticPropsでデータを取得

次にデータ取得部分を見てみましょう。ここではoffsetに注目してください。context.params.idでは[] (ブラケット)の値を取得することができます。このidの数値を元にして、offsetの値を決めます。例えば、blog/page/2の場合idが2になるので(2-1) * 5でoffset=5の状態を作ることができます。

client.get({ endpoint: "blog", queries: { offset: (id - 1) * 5, limit: 5 } });

開発サーバーを立ち上げて、下部にあるリストの2をクリックするとblog/page/2にアクセスできます。ここで5~1件目のデータが取得できました。

おわりに

今回はNext.jsのページネーションについて解説しました。ページネーションはWeb制作において重要なコンポーネントになります。ぜひ、この記事がお役に立てば嬉しいです。


-----

microCMSは日々改善を進めています。
ご意見・ご要望は管理画面右下のチャット、公式Twitterメールからお気軽にご連絡ください!
引き続きmicroCMSをよろしくお願いいたします!

まずは、無料で試してみましょう。

APIベースの日本製ヘッドレスCMS「microCMS」を使えば、 ものの数分でAPIの作成ができます。

microCMSを無料で始める

microCMSについてお問い合わせ

初期費用無料・14日間の無料トライアル付き。ご不明な点はお気軽にお問い合わせください。

お問い合わせ

microCMS公式アカウント

microCMSは各公式アカウントで最新情報をお届けしています。
フォローよろしくお願いします。

  • X
  • Discord
  • github

ABOUT ME

かみむら
フロントエンドエンジニア。テックブロガーでもあります。JAMstackアーキテクチャーやSPA(React、Vue)技術が好きです。