本記事では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でoffset
とlimit
を使ってコンテンツ数を絞っています。
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をよろしくお願いいたします!