0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

一覧画面が重い?ページネーションを最初に選ぶときの考え方(Prisma)

0
Last updated at Posted at 2026-07-30

この記事の対象読者

  • Prismaで一覧画面を作り始めた人
  • skiptake は使ったことがあるが、cursor はまだよく分からない人
  • ページネーションの選び方に迷っている人

本題に入る前に

この話は、投稿一覧、予約一覧、注文履歴など、件数が増える一覧画面を実装する人を想定しています。UIとしてページ番号が必要なのか、もっと見る形式でよいのかを考える開発担当者に向けた内容です。

最近、業務画面を作るときに、一覧画面の体験は思った以上に大事だと感じます。ユーザー一覧、予約一覧、注文履歴、問い合わせ一覧など、業務アプリには「大量のデータを探して確認する画面」がたくさんあります。

一覧画面は地味ですが、毎日使う人にとっては仕事場そのものです。ページを送るたびに遅い、同じデータがまた出る、さっき見た行が消える、となると小さなストレスが積み重なります。

最初は件数が少なくても、サービスが使われるほどデータは増えていきます。全部を一度に表示する作りのままだと、DBにも画面にも負担がかかります。この記事では、一覧を少しずつ表示するためのページネーションを、UI要件とデータ量の両方から考えます。

一覧画面でページを分けたくなる理由

一覧画面を作っていると、データが10件くらいのうちは何も困りません。全部表示しても軽いし、見た目も問題ありません。

でも、投稿、予約、ユーザー、注文履歴のようなデータはどんどん増えます。1万件のデータを一度に画面へ返すと、DBにもサーバーにもブラウザにも負担がかかります。ユーザーもそんな長い一覧は読み切れません。

そこで、データを少しずつ区切って表示します。これがページネーションです。本でたとえるなら、分厚い本を1ページずつ読むようなものです。

Prismaは、TypeScriptからDBを扱いやすくするORMです。SQLを直接たくさん書かなくても、findMany のようなメソッドでデータを取得できます。その中で一覧を区切る方法として、skip/takecursorを使う方法があります。

この記事では「どちらが偉いか」ではなく、「どんな画面ならどちらが自然か」を考えます。

ページネーションはSQLでも実装できますし、GraphQLやAPI設計でも考えるテーマです。この記事では、手元でイメージしやすいようにPrismaのコードで説明します。

offset pagination

offset paginationは、何件スキップして何件取るかを指定する方法です。

Prismaでは skiptake を使います。

const page = 3;
const perPage = 10;

const posts = await prisma.post.findMany({
  skip: (page - 1) * perPage,
  take: perPage,
  orderBy: {
    createdAt: "desc",
  },
});

分かりやすいので、管理画面のように「1ページ目、2ページ目、3ページ目」と移動したいUIに向いています。

ただし、データがとても多くなり、深いページまで移動すると、スキップする件数も増えます。また、一覧の途中でデータが追加・削除されると、ページをまたいだときに表示がずれることがあります。

cursor pagination

cursor paginationは、「このデータの次から取る」という考え方です。

const posts = await prisma.post.findMany({
  cursor: {
    id: "post_100",
  },
  skip: 1,
  take: 10,
  orderBy: {
    id: "asc",
  },
});

skip: 1 は、cursorに指定したレコード自身を結果から外すために使います。

cursor paginationは、無限スクロールや「もっと見る」ボタンと相性がよいです。

createdAtだけで並べると少し怖い

一覧では createdAt desc で並べたくなることが多いです。

ただ、同じ時刻のデータが複数あると順番が不安定になることがあります。実務では createdAtid のように、最後に一意になる値も含めて順序を安定させることを考えます。

const posts = await prisma.post.findMany({
  take: 10,
  orderBy: [
    { createdAt: "desc" },
    { id: "desc" },
  ],
});

ざっくり選び方

迷ったら、最初はこのくらいで考えるとよいです。

UIや条件 向いている方法
ページ番号で移動したい offset
件数が少ない管理画面 offset
無限スクロール cursor
データ量が多い一覧 cursor
更新が多く、表示ずれを減らしたい cursor

まとめ

Prismaのページネーションは、まず skip / take で始めても大丈夫です。

ただ、データ量が増えたり、無限スクロールのようなUIになったりしたら、cursor paginationも選択肢に入れるとよいです。

「どちらが正しいか」より、「その画面でユーザーがどう移動するか」から考えるのがおすすめです。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?