nextjs

静的Next.jsで「もっと見る」ボタンが使えない理由とページネーションを選んだ経緯

2026-04-19完了
静的Next.jsで「もっと見る」ボタンが使えない理由とページネーションを選んだ経緯

このブログのトップページに記事一覧を表示するとき、最初に「もっと見る」ボタンを実装しようとしました。

結果として採用したのはページネーションですが、その判断にたどり着くまでにいくつかの気づきがありました。同じところで詰まっている方の参考になればと思い、経緯を残しておきます。

最初に考えたのは「もっと見る」ボタンだった

記事一覧を表示するとき、最初に思い浮かんだのは「もっと見る」ボタンでした。

ページを開いたときに最初の10件だけ表示して、ボタンを押すと次の10件が追加で表示される、という動きです。多くのブログやニュースサイトで見かける、あの UI です。

ページ遷移なしで読み続けられる点がユーザーにとって使いやすいと思っていましたし、見た目としてもスッキリするイメージがありました。

なぜ「もっと見る」ボタンが使えないのか

実装方法を調べていく中で、静的サイトとの相性が悪いことがわかりました。

「もっと見る」ボタンの一般的な実装では、ボタンをクリックしたタイミングでサーバーに追加データを要求します。サーバーが次の10件分のデータを返して、画面に追加する、という流れです。

しかし現在のこのサイトは output: 'export' という設定で動作しています。これは Next.js がビルド時に HTML ファイルをすべて生成して、あとは Nginx が静的ファイルを配信するだけ、という仕組みです。ページが表示された後にサーバーと通信することができません。

つまり「クリックしたらサーバーからデータを取得する」という動きが、根本的にできない構造になっています。

無理やり実装する方法はあるが…

方法がないわけではありません。

全記事のデータをページ読み込み時に HTML に含めておいて、最初は10件だけ表示し、ボタンを押したら JavaScript で隠れている記事を表示する、という方法があります。

ただしこの方法には問題があります。記事が100件、200件と増えていくにつれて、最初のページ読み込みに含まれるデータ量が増え続けます。読者がまだ読んでいない記事のデータも最初からすべて読み込むことになるため、表示速度に影響が出てくる可能性があります。

小規模なうちは問題ないかもしれませんが、長期的な運用を考えると選びにくい方法でした。

ページネーションを選んだ

結果として、ページネーション(番号付きのページ送り)を選びました。

静的サイトでページネーションを実現する方法として、静的パス方式があります。ビルド時に各ページの HTML ファイルを事前に生成しておく方法です。

/          → 1ページ目の HTML(ビルド時に生成)
/page/2    → 2ページ目の HTML(ビルド時に生成)
/page/3    → 3ページ目の HTML(ビルド時に生成)

記事が増えてビルドを実行するたびに、必要なページ数分の HTML ファイルが自動的に生成されます。ページを開くときはサーバーと通信せず、すでに生成済みの HTML を表示するだけなので、静的サイトとの相性は完璧です。

実装で1つハマったこと

最初の実装では、 URL の ?page=2 を読み取る方式(searchParams 方式)で作っていました。

typescript
// 最初に実装した方式(これは静的サイトでは動かない) export default function Home({ searchParams }) { const currentPage = Number(searchParams?.page ?? 1); ... }

開発モード(npm run dev)では動いているように見えたのですが、静的エクスポート(output: 'export')では searchParams の動的な読み取りがサポートされていないことがわかりました。

| 方式 | URL の例 | 静的サイトで動くか | |---|---|---| | searchParams 方式(最初の実装) | /?page=2 | ❌ 動作しない | | 静的パス方式(最終的な実装) | /page/2 | ✅ 動作する |

開発モードで一見動いて見えるのに、ビルドして本番環境に出すと動かない、というのは気づきにくいポイントでした。

記事が1件しかない段階では問題が表面化しないため、今のタイミングで修正しておいてよかったと思っています。

もう1つのハマりどころ:記事が少ないときのエラー

静的パス方式では、 Next.js がビルド時にどのページを生成するかを generateStaticParams() という関数で伝える必要があります。

typescript
export function generateStaticParams() { // 2ページ目以降のページ番号を返す return [{ pageNum: '2' }, { pageNum: '3' }, ...]; }

問題は、記事が10件以下のときです。2ページ目以降が存在しないため、この関数が空の配列を返すことになります。するとビルド時にエラーになります。

Error: Page "/page/[pageNum]" is missing "generateStaticParams()"

対処として、記事が10件以下のときはダミーとして { pageNum: '2' } だけを返すようにしました。 /page/2 にアクセスしても notFound() が返るため、実際の動作に影響はありません。

typescript
if (filtered.length === 0) { return [{ pageNum: '2' }]; // ダミー:記事が10件以下のときのエラー対策 }

まとめ

今回の判断をひとことで整理すると、「静的サイトの制約に合わせた方法を選んだ」ということになります。

「もっと見る」ボタンは使いやすい UI ですが、静的サイトとの相性が悪い。ページネーションは少し古典的な印象もありますが、静的サイトで確実に動く方法として今のこのサイトには合っていると判断しました。

メインブログでは、実装の手順を詳しく解説しています。

【Next.jsブログ構築】トップページと記事ページのデザインを決定・実装する方法

この記事が役に立ったら、シェアしていただけると嬉しいです!

関連記事