Next.js の一覧と詳細ページ。最小構成サンプル
一覧から詳細へ辿る形は、ファイル4つで足ります。
動いているものを触る/demo/listファイル構成
並んでいるのは、上の画面をいま動かしている本物のファイルです。名前を押すと中身が出ます。
- app/
- [id]/
全ページの外側。本物のプロジェクトでは html と body をここで書きます
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "一覧と詳細の最小構成",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return <main>{children}</main>;
}- .tsx
- 画面を返すファイル。HTML のような書き方ができます
- .ts
- 画面を返さないファイル。処理とデータだけを置きます。ここに画面を書くと原因を名指ししないエラーで落ちます
- Build
- ビルド時に一度だけ動きます
- Server
- アクセスのたびにサーバーで動きます
- Browser
- 利用者の手元で動きます
角括弧がアドレスの可変部分になる
詳細ページを作るのに、ルーターの設定は要りません。フォルダ名を角括弧で囲むだけです。
app/page.tsx → /demo/list
app/[id]/page.tsx → /demo/list/boundary
/demo/list/cache
/demo/list/form
囲んだ名前がそのまま受け取れます。
export default async function Detail({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
ビルド時に作っておく
generateStaticParams は、「どの id でページを作っておくか」をビルドに教える関数です。
export async function generateStaticParams() {
const books = await listBooks()
return books.map((b) => ({ id: b.id }))
}
実機で確かめました。ビルドの一覧に3件ぶんが並びます。
├ /demo/list/[id]
│ ├ ● /demo/list/boundary
│ ├ ● /demo/list/cache
│ └ ● /demo/list/form
● は「ビルド時に作った」という印です。リクエストのたびに作り直しません。
- Buildid の一覧を作る
generateStaticParams がデータを読んで、作るべきアドレスを返す。
- Buildその数だけページを作る
3件なら3枚。ここまでで終わっている。
- Browserできたものを配る
アクセス時にサーバーは何も作らない。
書かなければどうなるか、というと落ちはしません。リクエストのたびに作られるようになるだけです。件数が読めているなら、書いておくほうが速く出せます。
知らない id で来たとき
const book = await findBook(id)
if (!book) notFound()
実機で確かめました。/demo/list/nonexistent は 404 を返します。
データはブラウザに届かない
app/data.ts を読んでいるのはサーバー側だけです。だからこの配列は、ブラウザには届きません。
実機で確かめました。ビルドしたものを検査して、著者名も本文も、配信される JavaScript には1件も含まれていませんでした。届いているのは、一覧に表示した題名だけです。
件数が3件でも3万件でも同じです。絞ってから送るか、送ってから絞るかの違いが、そのまま通信量の違いになります。
ここから足していくとき
- ページ送り。
searchParamsでページ番号を受け取ります。そこを読んだ時点で一覧は動的になります - 絞り込み。検索の最小構成にあります。そこで初めて Client Component が1つ要ります
- 更新。書き込む口を作るなら Server Function の呼び方の形になります
ここまでの3つのサンプルには、Client Component が1つもありません。次でようやく1つ出てきます。
入れていないもの
このまま本番に持っていかないでください。省いてあるのは次の点です。
- データベース。3件の配列を返しているだけです
- ページ送り。件数が増えたら一覧を区切る必要があります
- 並び替えと絞り込み。それは検索の最小構成で扱っています
- 更新。読むだけで、書き込む口はありません
出典
- nextjs.org/docs/app/api-reference/file-conventions/dynamic-routes
- nextjs.org/docs/app/api-reference/functions/generate-static-params
- nextjs.org/docs/app/api-reference/functions/not-found
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。