はじめに
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. 型変換とデフォルト値
page は string | undefined なので、数値に変換しつつデフォルト値を設定します。
const { page } = await searchParams;
const currentPage = Number(page) || 1;
解説:
-
pageがundefined→Number(undefined)はNaN→NaN || 1で 1 になる -
pageが"2"→Number("2")は2→2 || 1で 2 になる
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を制御する