Next.js App Routerでページネーション


概要

  • Next.jsのApp Routerでブログサイトを構築
  • /pages/1 /pages/2のようなURLで記事を並べたページネーションを実装

手順

記事一覧ページのはじめの一歩

/app/pages/[pageNum]/page.tsxを作って以下のようにする。

export default function Page({ params }: { params: { pageNum: number } }) {
  return <div>My Post: {params.pageNum}</div>
}

参考:https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#example

これで/pages/1``/pages/2にアクセスして表示できれば最初の一歩はOK。これを修正していく。

記事一覧の実装

  • ITEMS_SIZEで1ページに表示する記事数を指定
  • 全ての記事のメタデータの配列を取ってくる関数を定義(詳細は略)
  • 現在のページ番号とITEMS_SIZEをもとに、表示すべき記事を選別(配列をスライス)
  • スライスした配列をmapで回して、メタデータを表示(PostCardを定義してカード表示させる)
import { getSortedPostsData } from '@/utils/posts'
import PostCard from '@/app/components/PostsCard';

const ITEMS_SIZE = 5;

export default async function Page({ params }: { params: { pageNum: number } }) {
  const allPostsData = await getSortedPostsData();
  const currentPage = params.pageNum;

  const slicedPosts = allPostsData.slice(
    ITEMS_SIZE * (currentPage - 1),
    ITEMS_SIZE * currentPage
  );

  return (
    <>
      <h2>Posts</h2>
      {slicedPosts.map(({slug, date, title}) => (
        <PostCard key={slug} title={title} slug={slug} date={date}/>
      ))}
    </>
  )
}

ページネーションコンポーネントの定義

  • 記事一覧ページの番号の最大値を引数にとり、各記事一覧ページへのリンクを貼る
  • 現在のページの番号を引数にとって、現在どの番号のページにいるかわかるようCSSを調整する
import Link from 'next/link';

const Pagination = ({ maxPageNum, currentPageNum = 1 }) => {
  const pageNumArray = Array.from({ length: maxPageNum }, (_, i) => i + 1);

  return (
    <div className="flex items-center space-x-1 mt-8">
      {pageNumArray.map((page) => (
        <Link 
          href={`/pages/${page}`} 
          key={page}
          className={`px-4 py-2 border hover:bg-sky-900 hover:text-white ${
            currentPageNum == page && 'bg-sky-900 text-white'
          }`}
        >
          {page}
        </Link>
      ))}
    </div>
  );
};

export default Pagination;

ページネーションを記事一覧ページ内に

記事一覧ページの番号の最大値を計算して、Paginationの引数に渡せばOK。

export default async function Page({ params }: { params: { pageNum: number } }) {
  // 追加
  const maxPageNum = Math.ceil(allPostsData.length / ITEMS_SIZE)

  return (
    <>
      // 追加
      <Pagination maxPageNum={maxPageNum} currentPageNum={currentPage} />
    </>
  )
}

Page routerの時にあったgetStaticPropsがなくなって記述がシンプルになった?