みなさんこんにちは!!
やむちゃ(@hpfull_01)です。
本日はNext.jsとmicroCMSで作成したWebサイトにページネーションを実装しました!!
少し癖があったのでメモとして残しておきたいと思います。
も参照くださいませ。
前提
- Next.jsで既にアプリケーションを作っている
- Tailwind CSSを導入している(普通のCSSに置き換えて貰えばTailwind CSSである必要はないです。)
作っていくページネーションは本ブログ一覧ページで実装されているようなものです。
また、ソースコードを参考として載せておきます。
ページネーション用のコンポーネントを作成する
ページネーションを実装するのに追加したファイルは下記になります。場合によってはもっと細分化していった方がいいとは思うのですが、とりあえず今は最低限これでいいと思います。
- componets/Pagination.js
- pages/blogs/page/[id].js
ページネーション自体のコンポーネントと個別のページネーションページです。
まずはページネーションのコンポーネントを作っていきます。
import Link from 'next/link';
export const Pagination = ({ maxPageNumber, currentPageNumber }) => {
currentPageNumber = Number(currentPageNumber);
maxPageNumber = Number(maxPageNumber);
const prevPage = currentPageNumber - 1;
const nextPage = currentPageNumber + 1;
return (
<div className="flex px-3 my-12">
{currentPageNumber !== 1 && (
<Link href={`/blogs/page/${prevPage}`}>
<a>< Previous</a>
</Link>
)}
{currentPageNumber !== maxPageNumber && (
<Link href={`/blogs/page/${nextPage}`}>
<a className="ml-4">Next ></a>
</Link>
)}
</div>
);
};
軽く説明すると、現在のページ番号と最大ページのpropsを受け取って現在のページが1ならPreviousボタンは表示せず、現在のページが最大ページと同じならNextボタンを表示しないという感じです。
TypeScriptだと型定義できるため、Propsで受け取るときにnumber型を指定すると良いかと思います。
(先ほど載せたソースコードではTypeScriptで実装しています。)
では、一旦このコンポーネントを使って一覧ページに入れてみます。
import Image from 'next/image';
import Blog from '../components/Blog';
import { client } from '../libs/client';
import { Pagination } from '../components/Pagination';
export default function Home({ blog, totalCount }) {
return (
<Layout title="Home">
<p className="text-4xl m-10">適当</p>
<Blog blog={blog} />
<Pagination currentPageNumber={1} maxPageNumber={Math.ceil(totalCount / 4)} />
</Layout>
);
}
export const getStaticProps = async () => {
const offset = 0;
const limit = 4;
const queries = { offset: offset, limit: limit };
const data = await client.get({ endpoint: 'blogs', queries: queries });
return {
props: {
blog: data.contents,
totalCount: data.totalCount,
},
};
};
microCMSではAPIをリスト型でもらっていると、data.totalCountを受け取ることができます。これは取得したコンテンツの数ではなく、APIに紐づいている全てのコンテンツの数です。あとはget関数を使うときにクエリーを混ぜ混ぜできます。公式のソースコードでも確認ができます。ここでoffsetとlimitを渡してAPIをフェッチすることで、最後に受け取ったブログの次のやつから4つを取得することができるのです。
ただし、このままでは、/blogs/page/${i}の部分を実装していないので404になってしまいます。
{i}の部分は
const numId = context.params.id;
で取得しています。例えば、/blogs/page/2
のときnumIdに入ってくるのは2です。
/blogs/page/${i}
import { client } from '../../../libs/client';
import Layout from '../../../components/Layout';
import Blog from '../../../components/Blog';
import { Pagination } from '../../../components/Pagination';
export default function BlogPageId({ blog, totalCount, currentPageNumber }) {
return (
<Layout title="blogpage">
<Blog blog={blog} />
<Pagination currentPageNumber={currentPageNumber} maxPageNumber={Math.ceil(totalCount / 4)} />
</Layout>
);
}
export const getStaticPaths = async () => {
const range = (start, end) => [...Array(end - start + 1)].map((_, i) => start + i);
const data = await client.get({ endpoint: 'blogs' });
const { totalCount } = data;
const paths = range(1, Math.ceil(totalCount / 4)).map((i) => `/blogs/page/${i}`);
return { paths, fallback: false };
};
export const getStaticProps = async (context) => {
const numId = context.params.id;
const offset = (numId - 1) * 4;
const limit = 4;
const queries = { offset: offset, limit: limit };
const data = await client.get({ endpoint: 'blogs', queries: queries });
return {
props: {
blog: data.contents,
totalCount: data.totalCount,
currentPageNumber: numId,
},
};
};
まず、getStaticPathsはビルドの前にパスを作ってくれます。例えば、totalContentが20個であったらlimitが4のとき作成されるパスは、以下のようになります。
- blogs/page/1
- blogs/page/2
- blogs/page/3
- blogs/page/4
- blogs/page/5
まとめ:Next.jsでページネーションを実装してみた
Next.jsで自作サイトを作り、コンテンツが増えていくとページネーションのような物を実装してみたくなりますよね。この記事を参考にぜひ取り入れてみてください。
最後までご覧いただきありがとうございました。
コメント