ページネーションの仕組み

ページネーションの仕組み

投稿日: 2025年03月04日

学習振り返り
要約
  • ページネーションはバックエンドとフロントエンドが連携してデータを取得・表示する仕組みである。
  • バックエンドはクエリパラメータからページ情報を取得し、全体件数を元にデータを返す。
  • フロントエンドはページ番号を管理し、ユーザー操作に応じてデータをリクエスト・表示する流れが重要である。
音声で記事を再生

はじめに

ページネーションの実装は、オリジナルアプリで挑戦する方も多いかと思います。
私は実務課題で初めて実装しました。
ページネーションのロジックがよくわからなくて、娘の習い事の待ち時間にスマホで調べた記憶があります。

これからページネーション実装する方もいらっしゃると思うので、この記事では処理の流れを中心にバックエンドとフロントエンド両方について触れて解説してみたいと思います。

バックエンド

1ページ当たりのデータ数を決める

バックエンドで1ページあたり30件などと固定する場合もあれば、フロントエンドから取得件数を指定する場合もあります。
取得する場合はクエリパラメータで受け取ります。

フロントエンドで表示されているページを受け取る

こちらもクエリパラメータで受け取り、データを取得します。

全体件数(totalCount)を取得し、ページ数を計算

フロントエンドの仕様にもよりますが、全体件数(totalCount)を取得することで、現在の表示件数や全ページ数を計算できるようになります。

コード例

export const GET = async (request: NextRequest) => {
  const prisma = await buildPrisma();
  try {
    const url = new URL(request.url);
   //クエリパラメータのpageを取得、なければ0ページ目とする
    const page = parseInt(url.searchParams.get("page") || "0");
   //1ページ辺り15データ
    const pageSize = 15;
  //何件スキップするか定義
    const skip = page * pageSize;
  //何件取得するか定義(フロント側から取得する場合はpageSize不要で取得した値を代入)
    const take = pageSize;
  
  //検索機能もある場合は検索ワード取得して変数に格納
  //ここでは省略するが、whereConditionにwhere句の内容いれている

    const [recipeArticles, totalCount] = await Promise.all([
      prisma.recipeArticle.findMany({
     where: whereCondition//絞込みがある場合のみ
        skip,
        take,
        orderBy: { createdAt: "desc" },
        include: {
          maltArticle: true,
          user: true,
        },
      }),
   //全件数を取得する
      prisma.recipeArticle.count({
        where: whereCondition,//絞込みがある場合のみ
      }),
    ]);
  //何ぺージあるかを計算する
    const totalPages = Math.ceil(totalCount / take);

  //返却する

こんな感じです。

次にフロント側です。

フロントエンド

ページ番号を管理する

現在のクエリパラメータのpageをステートで管理します。
要件によっては、URL操作でページを切り替えられるようにすることもあります。
「次へ」「前へ」ボタンを押すたびに page の値を変更し、リクエストを送ってデータを取得・表示する流れになります。

エンドポイント

下記のようにしてリクエストします。

/api/recipes?page=${currentPage}

これでcurrentPageの値をバックエンドに渡せて現在のページに応じたデータを受け取ることが出来ます。

コード例

//useSearchParamsState.ts
"use client";
import { useSearchParams } from "next/navigation";
import { useState, useEffect } from "react";

export const useSearchParamsState = () => {
  //URLのpageを取得、なければ0にして文字列→数値に変える
  const searchParams = useSearchParams();
  const page = parseInt(searchParams?.get("page") || "0", 10);

  //URLのpageをステートにセットする
  const [currentPage, setCurrentPage] = useState(page);

 //ボタン操作等で現在のページが変更されたらURLのpageも変更する
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    params.set("page", currentPage.toString());
    const newUrl = `${window.location.pathname}?${params.toString()}`;
    window.history.replaceState({}, "", newUrl);
  }, [currentPage]);

  return {
    currentPage,
    setCurrentPage,
  };
};

ページネーションはライブラリを使うと便利

react-paginateを使用して実装する例です。

"use client";
import ReactPaginate from "react-paginate";

interface Props {
  //バックエンドで用意したtotalPages
  pageCount: number;
 //フックで定義したステート
  currentPage: number;
  //フックで定義したステートの更新関数
  setCurrentPage: (currentPage: number) => void;
}
export const Paginate: React.FC<Props> = ({
  pageCount,
  currentPage,
  setCurrentPage,
}) => {
  const handlePageChange = (e: { selected: number }) => {
    setCurrentPage(e.selected);
  };
  const baseClassName =
    "py-1 px-2 w-8 border rounded text-center block border-dark_brown";
  return (
    <div className="py-3 w-full bg-white/30 flex justify-end">
      <ReactPaginate
     //前のページへのボタンのラベル
        previousLabel={"前"}
     //次のページへのボタンのラベル
        nextLabel={"次"}
     //総ページ数
        pageCount={pageCount}
     //最初と最後に表示するページ番号の数
        marginPagesDisplayed={2}
     //現在のページの前後に表示するページ番号の数
        pageRangeDisplayed={5}
     // ページ変更時に実行する関数
        onPageChange={handlePageChange}
     //現在のページを強制的に指定する
        forcePage={currentPage}
     //スタイル
        containerClassName={"flex gap-2"}
        previousLinkClassName={`${baseClassName} mr-4 ml-3`}
        nextLinkClassName={`${baseClassName} ml-4`}
        pageLinkClassName={baseClassName}
        activeLinkClassName={"bg-gray_bg"}
      />
    </div>
  );
};

これだけで下記のようなページネーションの実装が出来ます!

ページネーションの仕組み|ShiftBブログ

まとめ

ページネーションは、バックエンドとフロントエンドが連携して動く仕組みです。

  • バックエンド は、指定された page などのクエリパラメータをもとにデータを取得し、全体件数 (totalCount) も返す。

  • フロントエンド は、現在のページ番号を管理し、リクエストを送信する。レスポンスを元にデータを表示し、ユーザー操作に応じてページを切り替える。

ロジックが理解できれば、ライブラリを活用することでスムーズに実装できます。

おわりに

どんなロジックなのかザックリでも理解できると、その実現のためにどんな処理をしたらいいかわかってきて自分で書けるようになると思いますので、簡潔にまとめたつもりです。

ロジックを理解するためには、まずコードを見ずに「何をすればよいか」を考えるのが効果的かもしれません。

実務では、フロントエンドの実装担当であれば、「クエリパラメータでpageを送って」 などと指定されることが多いと思います。
page以外にlimit(取得する件数)や検索機能もあると、keyword(検索ワード),from,to(日付絞込み)などをクエリパラメータで渡すこともあると思います。
そのため、フロントエンドは 指定された通りにリクエストを送り、返ってきたデータを表示、ユーザー操作に応じてpageの切替をし、データを再取得して表示するという流れになります。

参考になれば嬉しいです!

シェア!

Threads
user
吉本茜
山口在住/二児の母
記事一覧に戻る
Threads
0