レイアウトとページ
Next.js はファイルシステムベースのルーティングを使用します。つまり、フォルダとファイルを使用してルートを定義できます。このページでは、レイアウトとページを作成し、それらをリンクする方法について説明します。
ページの作成
ページは、特定のルートでレンダリングされる UI です。ページを作成するには、app ディレクトリ内にpage ファイルを追加し、React コンポーネントをデフォルトエクスポートしてください。たとえば、インデックスページ(/)を作成するには:
export default function Page() {
return <h1>Hello Next.js!</h1>
}レイアウトの作成
レイアウトは、複数のページ間で共有される UI です。ナビゲーション時に、レイアウトはステータスを保持し、対話的で、再レンダリングされません。
layout ファイルから React コンポーネントをデフォルトエクスポートしてレイアウトを定義できます。このコンポーネントは children プロップを受け入れる必要があります。これはページまたは別のレイアウトです。
たとえば、インデックスページを子として受け入れるレイアウトを作成するには、app ディレクトリ内に layout ファイルを追加します:
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
{/* レイアウト UI */}
{/* ページまたはネストされたレイアウトをレンダリングしたい場所に children を配置 */}
<main>{children}</main>
</body>
</html>
)
}上記のレイアウトはルートレイアウトと呼ばれます。これは app ディレクトリのルートで定義されているためです。ルートレイアウトは必須であり、html および body タグを含める必要があります。
ネストされたルートの作成
ネストされたルートは、複数の URL セグメントで構成されるルートです。たとえば、/blog/[slug] ルートは 3 つのセグメントで構成されています:
/(ルートセグメント)blog(セグメント)[slug](リーフセグメント)
Next.js では:
- フォルダは、URL セグメントにマップするルートセグメントを定義するために使用されます。
- ファイル(
pageやlayoutなど)は、セグメント用に表示される UI を作成するために使用されます。
ネストされたルートを作成するには、フォルダを相互にネストできます。たとえば、/blog のルートを追加するには、app ディレクトリに blog という名前のフォルダを作成します。次に、/blog を公開アクセス可能にするには、page.tsx ファイルを追加します:
// ダミーインポート
import { getPosts } from '@/lib/posts'
import { Post } from '@/ui/post'
export default async function Page() {
const posts = await getPosts()
return (
<ul>
{posts.map((post) => (
<Post key={post.id} post={post} />
))}
</ul>
)
}フォルダのネストを続けてネストされたルートを作成できます。たとえば、特定のブログ投稿のルートを作成するには、blog 内に新しい [slug] フォルダを作成し、page ファイルを追加します:
function generateStaticParams() {}
export default function Page() {
return <h1>Hello, Blog Post Page!</h1>
}フォルダ名を角括弧で囲む(例:[slug])と、動的ルートセグメントが作成されます。これは、データから複数のページを生成するために使用されます。例えば、ブログ投稿、商品ページなどです。
レイアウトのネスト
デフォルトでは、フォルダの階層内のレイアウトもネストされます。つまり、children プロップを使用して子レイアウトをラップします。特定のルートセグメント(フォルダ)内に layout を追加することで、レイアウトをネストできます。
たとえば、/blog ルートのレイアウトを作成するには、blog フォルダ内に新しい layout ファイルを追加します。
export default function BlogLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}上記の 2 つのレイアウトを組み合わせる場合、ルートレイアウト(app/layout.js)はブログレイアウト(app/blog/layout.js)をラップし、そのレイアウトはブログ(app/blog/page.js)とブログ投稿ページ(app/blog/[slug]/page.js)をラップします。
動的セグメントの作成
動的セグメントを使用すると、データから生成されるルートを作成できます。たとえば、個々のブログ投稿ごとにルートを手動で作成する代わりに、動的セグメントを作成してブログ投稿データに基づいてルートを生成できます。
動的セグメントを作成するには、セグメント(フォルダ)名を角括弧で囲みます:[segmentName]。たとえば、app/blog/[slug]/page.tsx ルートでは、[slug] が動的セグメントです。
export default async function BlogPostPage({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const post = await getPost(slug)
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
)
}動的セグメントとparamsプロップについて詳しく学習してください。
動的セグメント内のネストされたレイアウトも params プロップにアクセスできます。
サーチパラムを使用したレンダリング
Server Component ページでは、searchParamsプロップを使用してサーチパラムにアクセスできます:
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}) {
const filters = (await searchParams).filters
}searchParams を使用すると、サーチパラムをリクエストから読み込む必要があるため、ページは動的レンダリングにオプトインされます。
Client Components は useSearchParamsフックを使用してサーチパラムを読み込むことができます。
静的レンダリングおよび動的レンダリングルートでの useSearchParams についてさらに学習してください。
何を使用し、いつ使用するか
- ページ用のデータをロードするためにサーチパラムが必要な場合は、
searchParamsプロップを使用してください(例:ページネーション、データベースからのフィルタリング)。 - サーチパラムがクライアント上でのみ使用される場合は、
useSearchParamsを使用してください(例:プロップを使用して既にロードされたリストのフィルタリング)。 - 小さな最適化として、再レンダリングをトリガーせずにサーチパラムを読み込むために、コールバックまたはイベントハンドラーで
new URLSearchParams(window.location.search)を使用できます。
ページ間のリンク
<Link> コンポーネントを使用してルート間をナビゲートできます。<Link> は、HTML <a> タグを拡張してプリフェッチとクライアント側ナビゲーションを提供する組み込み Next.js コンポーネントです。
たとえば、ブログ投稿のリストを生成するには、next/link から <Link> をインポートし、href プロップをコンポーネントに渡します:
import Link from 'next/link'
export default async function Post({ post }) {
const posts = await getPosts()
return (
<ul>
{posts.map((post) => (
<li key={post.slug}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}補足:
<Link>は、Next.js でルート間をナビゲートするための主な方法です。より高度なナビゲーションのために、useRouterフックを使用することもできます。
ルートプロップヘルパー
Next.js は、ルート構造から params および名前付きスロットを推論するユーティリティタイプを公開します:
- PageProps:
paramsとsearchParamsを含むpageコンポーネントのプロップ。 - LayoutProps:
childrenおよび任意の名前付きスロット(例:@analyticsのようなフォルダ)を含むlayoutコンポーネントのプロップ。
これらはグローバルに利用可能なヘルパーであり、next dev、next build または next typegen の実行時に生成されます。
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params
return <h1>Blog post: {slug}</h1>
}export default function Layout(props: LayoutProps<'/dashboard'>) {
return (
<section>
{props.children}
{/* app/dashboard/@analytics がある場合、型指定されたスロットとして表示されます: */}
{/* {props.analytics} */}
</section>
)
}補足
- 静的ルートは
paramsを{}に解決します。PageProps、LayoutPropsはグローバルヘルパーです — インポートは不要です。- 型は
next dev、next buildまたはnext typegen中に生成されます。