1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Next.js】searchParamsのawait必須化とページネーション実装

1
Posted at

はじめに

Next.js 15以降では searchParams が Promise になり、await が必須になりました。管理画面の注文一覧にページネーションを実装する際に、await の位置や型変換でハマったので、正しいパターンをまとめます。

この記事の対象読者・前提条件

対象読者

  • Next.js 15で searchParams の扱いが変わって戸惑っている方
  • Server Component でページネーションを実装したい方

前提条件

  • Next.js 15以降(App Router)を使用
  • Server Component の基本を理解している

実装

1. searchParams の正しい await の位置

Next.js 15では searchParams 自体が Promise なので、まず searchParams を await してからプロパティにアクセスします。

// ❗ 間違い:プロパティに await している
const page = await searchParams.page;

// ✅ 正しい:Promise を先に解決してから .page にアクセス
const { page } = await searchParams;

解説: searchParams.page は Promise のプロパティなので undefined になります。分割代入(デストラクチャリング)でまとめて取得するのがスッキリ書けます。

2. 型変換とデフォルト値

pagestring | undefined なので、数値に変換しつつデフォルト値を設定します。

const { page } = await searchParams;
const currentPage = Number(page) || 1;

解説:

  • pageundefinedNumber(undefined)NaNNaN || 11 になる
  • page"2"Number("2")22 || 12 になる

page がない場合は1ページ目として扱えばいいので、redirect でリダイレクトする必要はありません。

3. 条件付きページネーションリンク

「前へ」「次へ」ボタンを条件に応じて表示/非表示するパターンです。

// ❗ 間違い:href の中に条件式を入れている
<Link href={`...` && currentPage > 1}>前へ</Link>

// ✅ 正しい:Link 自体を条件付きで表示
{currentPage > 1 && (
  <Link href={`/admin/orders?page=${currentPage - 1}`}>前へ</Link>
)}
{currentPage < totalPages && (
  <Link href={`/admin/orders?page=${currentPage + 1}`}>次へ</Link>
)}

解説: {条件 && <コンポーネント>} は React の条件付きレンダリングの定番パターンです。条件が true なら Link を表示、false なら何も表示しない、という書き方です。

4. totalCount の取得

const totalCount = await prisma.order.count();
const totalPages = Math.ceil(totalCount / PAGE_SIZE);

全体の実装例

const PAGE_SIZE = 10;

export default async function AdminOrdersPage({
  searchParams,
}: {
  searchParams: Promise<{ page?: string }>
}) {
  const { page } = await searchParams;
  const currentPage = Number(page) || 1;
  const totalCount = await prisma.order.count();
  const totalPages = Math.ceil(totalCount / PAGE_SIZE);

  const orders = await prisma.order.findMany({
    skip: (currentPage - 1) * PAGE_SIZE,
    take: PAGE_SIZE,
    orderBy: { createdAt: "desc" },
  });

  return (
    <>
      {orders.map((order) => (
        <div key={order.id}>...</div>
      ))}
      {currentPage > 1 && (
        <Link href={`/admin/orders?page=${currentPage - 1}`}>前へ</Link>
      )}
      {currentPage < totalPages && (
        <Link href={`/admin/orders?page=${currentPage + 1}`}>次へ</Link>
      )}
    </>
  );
}

まとめ

  • Next.js 15では searchParams 自体を await してからプロパティにアクセスする
  • Number(page) || 1 で型変換とデフォルト値を同時に処理できる
  • 条件付きレンダリング {条件 && <Component>} でページネーションUIを制御する

参考

1
1
2

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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?