📄

page(ページ番号)とlimit(表示件数)でのページネーション設計を考える

2024/01/13に公開

こんにちは、AIQ株式会社のフロントエンドエンジニアのまさぴょんです!
今回は、page(ページ番号)とlimit(表示件数)でのページネーション設計について、解説します。

ページ番号で区切るページネーションの設計をする

ページ番号で区切るページネーションの処理フロー・ステップをまとめると、次のとおりです。

ページ番号で区切るページネーションの処理フロー
  1. FrontEndから、page(ページ番号)とlimit(表示件数)で、BackEndにGET通信をする。
    • 例:https://robotama-api.com?limit=5&page=1
  2. BackEnd(API)で、page(ページ番号)とlimit(表示件数)から、offset(取得位置)を計算する。
    • 通常、offset = (page - 1) ✖ limitの式で計算されます。
    • たとえば、limit=5 と page=2 の場合、offset = (2-1) ✖️ 5 = 5となり、5番目のアイテムから表示を開始します。
  3. itemList(該当アイテム)とallCount(アイテム総数)を取得するSQLクエリを作成・実行する。
    • 例:SELECT * FROM table LIMIT 5 OFFSET 5;
    • 例:SELECT COUNT(id) FROM テーブル名;
  4. itemList(該当アイテム)とallCount(アイテム総数)をFrontEndに返却する。
  5. FrontEndに処理が戻って、ページネーション関連のデータの計算をする。
    • return(実行結果)で、itemList(該当アイテム), allCount(総アイテム数)を取得する。
    • allCount(総アイテム数)と、1ページのlimit(表示件数)が決まっていれば、allPage(総ページの数)は計算できる。
    • 例えば、allCount=36, limit=5なら 36 / 5 = 7 あまり 1 で、8 ページ目までページを作成します。

上記のような処理フローで今回は、設計・実装を進めていきます。

登場する要素を整理する

先述の処理フローで、概要は掴めたと思いますが、登場する要素を整理すると、次のとおりです。

登場する要素まとめ
  1. limit(表示件数)の設定:この値は1ページに表示したいアイテムの数を定義します。
    • 例えば、limit=5は 1ページに5件のアイテムを表示することを意味します。
    • FrontEndで計算します。
  2. page(ページ番号):ユーザーがアクセスしているページ番号です。
    • 例えば、page=2はユーザーが2ページ目を見ていることを示します。
    • FrontEndで計算します。
  3. offset(取得位置):表示を開始するアイテムのインデックス・取得位置
    • 通常、offset = (page - 1) ✖️ limitの式で計算されます。
    • たとえば、limit=5 と page=2 の場合、offset = (2-1) ✖️ 5 = 5となり、5番目のアイテムから表示を開始します。
    • BackEndで計算します。
  4. allCount(アイテムの総数): ページに表示するアイテムの総数です。
    • SQLのCOUNTを使って計算するのが一般的です。
    • BackEndで計算します。
  5. allPage(ページの総数):ページの総数です。
    • 例えば、allCount=36, limit=5なら 36 / 5 = 7 あまり 1 で、8 ページ目までページを作成します。
    • FrontEndで計算します。

FrontEndの実装のポイントまとめ

FrontEnd側の処理ポイントをまとめると、次のとおりです。

事例として、FrontEnd(Nuxt・Vueの場合)のComponent内の初期値の状態は、次のような内容です。

itemList.vue
  data() {
    return {
      /** ページに表示する MyItem List */
      pageItems: [],
      /** 選択中の今のページ: 初期値は 1 */
      currentPage: 1,
      /** 1ページに表示する上限 */
      itemLimit: 5,
      /** アイテムの総数 */
      allCount: 0,
      /** すべてのページ数 */
      allPage: 0,
    };
  },

FrontEnd(Nuxt・Vueの場合)のページネーションのFetch処理は、次のような内容です。

/** 表示中のページのアイテムリストを取得する */
async getPageItemList(userId) {
  await this.$axios
    .get("/api/myItem/pageNation", {
      params: {
        user_id: userId,
        limit: this.itemLimit,
        page: this.currentPage,
      },
    })
    .then((res) => {
      // 今のページに表示するアイテムをセット
      this.pageItems = res.data.itemList;
      /** アイテムの総数 */
      const allCount = res.data.allCount;
      // アイテムの総数をセット
      this.allCount = allCount;
      // ページ総数をセット (あまりは切り上げる)
      this.allPage = Math.ceil(allCount / this.itemLimit);
    })
    .catch((err) => {
      console.error(err);
      // this.$router.push('/errorPage')
    });
},

総ページ数の計算の際には、あまりは切り上げて計算する点に注意です。

Math.ceil(allCount / this.itemLimit);

BackEndの実装のポイントまとめ

BackEnd側(APIとDB)の処理ポイントをまとめると、次のとおりです。

事例として、API(Express)のController処理を抜粋すると次のような処理です。

/** My Item List を取得する Controller Ver. ページネーション */
exports.getMyItemsPageNation = async (req, res) => {
  try {
    /** User ID */
    const userId = req.query.user_id;
    /** 取得するアイテム数(上限値) */
    const limit = req.query.limit;
    /** ページ番号 */
    const page = req.query.page;
    /** 取得位置 */
    const offset = limit * (page - 1);
    /** User の アイテムの総数 */
    const allCount = await productManageService.getMyItemsAllCount(userId);
    console.log("allCount Result", allCount);
    /** 指定ページの My Item List */
    const itemList = await productManageService.getMyItemsPageNation(
      userId,
      limit,
      offset
    );
    res.status(200).send({
      data: {
        itemList,
        allCount,
      },
    });
  } catch (err) {
    logger.error(req, err);
    res.status(200).send({
      error_code: 400,
      error: "get myItems error",
    });
  }
};

まとめ

ページネーションの設計は、今後も使えそうな経験なので、学べてよかったです。

個人で、Blogもやっています、よかったら見てみてください。

https://masanyon.com/

注意事項

この記事は、AIQ 株式会社の社員による個人の見解であり、所属する組織の公式見解ではありません。

求む、冒険者!

AIQ株式会社では、一緒に働いてくれるエンジニアを絶賛、募集しております🐱🐹✨

詳しくは、Wantedly (https://www.wantedly.com/companies/aiqlab)を見てみてください。

参考・引用

https://zenn.dev/manase/scraps/aade49469f4220

AIQ Tech Blog (有志)

Discussion