layout.js
layout
ファイルは、Next.js アプリケーションでレイアウトを定義するために使用されます。
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}
export default function DashboardLayout({ children }) {
return <section>{children}</section>
}
ルートレイアウト は、ルート app
ディレクトリ内の最上位のレイアウトです。<html>
タグや <body>
タグ、その他のグローバルに共有される UI を定義するために使用されます。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
リファレンス
Props
children
(必須)
レイアウトコンポーネントは children
プロップを受け取り、使用する必要があります。レンダリング時、children
にはレイアウトがラップするルートセグメントが含まれます。これには主に子の Layout または Page のコンポーネントが含まれますが、Loading や Error などの特別なファイルも含まれる場合があります。
params
(任意)
ルートセグメントからそのレイアウトまでの 動的ルートパラメータ オブジェクトを含む Promise です。
export default async function Layout({
params,
}: {
params: Promise<{ team: string }>
}) {
const { team } = await params
}
export default async function Layout({ params }) {
const { team } = await params
}
例のルート | URL | params |
---|---|---|
app/dashboard/[team]/layout.js | /dashboard/1 | Promise<{ team: '1' }> |
app/shop/[tag]/[item]/layout.js | /shop/1/2 | Promise<{ tag: '1', item: '2' }> |
app/blog/[...slug]/layout.js | /blog/1/2 | Promise<{ slug: ['1', '2'] }> |
params
プロップは Promise です。値を取得するにはasync/await
または React のuse
関数を使用する必要があります。- バージョン14以前では、
params
は同期プロップでした。後方互換性のために、Next.js 15でも同期的にアクセスできますが、この動作は将来非推奨になります。
- バージョン14以前では、
ルートレイアウト
app
ディレクトリには、必ずルート app/layout.js
を含める必要があります。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>{children}</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}
- ルートレイアウトは
<html>
タグと<body>
タグを定義する必要があります。<title>
や<meta>
などの<head>
タグを手動でルートレイアウトに追加するべきではありません。代わりに、Metadata API を使用してください。この API はストリーミングや<head>
要素の重複排除などの高度な要件を自動的に処理します。
- ルートグループ を使用して複数のルートレイアウトを作成できます。
- 複数のルートレイアウト間をナビゲートすると、フルページロードが発生します(クライアントサイドナビゲーションとは異なります)。例えば、
app/(shop)/layout.js
を使用する/cart
からapp/(marketing)/layout.js
を使用する/blog
にナビゲートすると、フルページロードが発生します。これは複数のルートレイアウトにのみ適用されます。
- 複数のルートレイアウト間をナビゲートすると、フルページロードが発生します(クライアントサイドナビゲーションとは異なります)。例えば、
注意点
リクエストオブジェクト
レイアウトはナビゲーション時にクライアント側でキャッシュされ、不要なサーバーリクエストを回避します。
レイアウト は再レンダリングされません。ページ間をナビゲートする際の不要な計算を避けるためにキャッシュされ、再利用されます。レイアウトが生のリクエストにアクセスできないように制限することで、Next.js はレイアウト内でパフォーマンスに悪影響を与える可能性のある低速または高コストなユーザーコードの実行を防ぎます。
リクエストオブジェクトにアクセスするには、Server Components および Functions で headers
と cookies
API を使用できます。
import { cookies } from 'next/headers'
export default async function Layout({ children }) {
const cookieStore = await cookies()
const theme = cookieStore.get('theme')
return '...'
}
import { cookies } from 'next/headers'
export default async function Layout({ children }) {
const cookieStore = await cookies()
const theme = cookieStore.get('theme')
return '...'
}
クエリパラメータ
レイアウトはナビゲーション時に再レンダリングされないため、古くなる可能性のある検索パラメータにアクセスできません。
更新されたクエリパラメータにアクセスするには、Page の searchParams
プロップを使用するか、Client Component 内で useSearchParams
フックを使用して読み取ることができます。Client Component はナビゲーション時に再レンダリングされるため、最新のクエリパラメータにアクセスできます。
'use client'
import { useSearchParams } from 'next/navigation'
export default function Search() {
const searchParams = useSearchParams()
const search = searchParams.get('search')
return '...'
}
'use client'
import { useSearchParams } from 'next/navigation'
export default function Search() {
const searchParams = useSearchParams()
const search = searchParams.get('search')
return '...'
}
import Search from '@/app/ui/search'
export default function Layout({ children }) {
return (
<>
<Search />
{children}
</>
)
}
import Search from '@/app/ui/search'
export default function Layout({ children }) {
return (
<>
<Search />
{children}
</>
)
}
パス名
レイアウトはナビゲーション時に再レンダリングされないため、古くなる可能性のあるパス名にアクセスできません。
現在のパス名にアクセスするには、Client Component 内で usePathname
フックを使用して読み取ることができます。Client Component はナビゲーション時に再レンダリングされるため、最新のパス名にアクセスできます。
import { Breadcrumbs } from '@/app/ui/Breadcrumbs'
export default function Layout({ children }) {
return (
<>
<Breadcrumbs />
<main>{children}</main>
</>
)
}
import { Breadcrumbs } from '@/app/ui/Breadcrumbs'
export default function Layout({ children }) {
return (
<>
<Breadcrumbs />
<main>{children}</main>
</>
)
}
データの取得
レイアウトは children
にデータを渡すことができません。ただし、同じデータをルートで複数回フェッチし、React の cache
を使用してリクエストを重複排除することができます。これはパフォーマンスに影響を与えません。
あるいは、Next.js で fetch
を使用すると、リクエストは自動的に重複排除されます。
export async function getUser(id: string) {
const res = await fetch(`https://.../users/${id}`)
return res.json()
}
import { getUser } from '@/app/lib/data'
import { UserName } from '@/app/ui/user-name'
export default async function Layout({ children }) {
const user = await getUser('1')
return (
<>
<nav>
{/* ... */}
<UserName user={user.name} />
</nav>
{children}
</>
)
}
import { getUser } from '@/app/lib/data'
import { UserName } from '@/app/ui/user-name'
export default async function Layout({ children }) {
const user = await getUser('1')
return (
<>
<nav>
{/* ... */}
<UserName user={user.name} />
</nav>
{children}
</>
)
}
import { getUser } from '@/app/lib/data'
import { UserName } from '@/app/ui/user-name'
export default async function Page() {
const user = await getUser('1')
return (
<div>
<h1>Welcome {user.name}</h1>
</div>
)
}
import { getUser } from '@/app/lib/data'
import { UserName } from '@/app/ui/user-name'
export default async function Page() {
const user = await getUser('1')
return (
<div>
<h1>Welcome {user.name}</h1>
</div>
)
}
子セグメントへのアクセス
レイアウトは自身より下のルートセグメントにアクセスできません。すべてのルートセグメントにアクセスするには、Client Component で useSelectedLayoutSegment
または useSelectedLayoutSegments
を使用できます。
import { NavLink } from './nav-link'
import getPosts from './get-posts'
export default async function Layout({
children,
}: {
children: React.ReactNode
}) {
const featuredPosts = await getPosts()
return (
<div>
{featuredPosts.map((post) => (
<div key={post.id}>
<NavLink slug={post.slug}>{post.title}</NavLink>
</div>
))}
<div>{children}</div>
</div>
)
}
import { NavLink } from './nav-link'
import getPosts from './get-posts'
export default async function Layout({ children }) {
const featuredPosts = await getPosts()
return (
<div>
{featuredPosts.map((post) => (
<div key={post.id}>
<NavLink slug={post.slug}>{post.title}</NavLink>
</div>
))}
<div>{children}</div>
</div>
)
}
例
メタデータ
metadata
オブジェクト または generateMetadata
関数 を使用して、title
や meta
などの <head>
HTML 要素を変更できます。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Next.js',
}
export default function Layout({ children }: { children: React.ReactNode }) {
return '...'
}
export const metadata = {
title: 'Next.js',
}
export default function Layout({ children }) {
return '...'
}
知っておくと良いこと:
<title>
や<meta>
などの<head>
タグを手動でルートレイアウトに追加するべきではありません。代わりに、Metadata API を使用してください。この API はストリーミングや<head>
要素の重複排除などの高度な要件を自動的に処理します。
アクティブなナビゲーションリンク
usePathname
フックを使用して、ナビゲーションリンクがアクティブかどうかを判断できます。
usePathname
はクライアントフックであるため、ナビゲーションリンクを Client Component に抽出し、レイアウトにインポートする必要があります:
import { NavLinks } from '@/app/ui/nav-links'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<NavLinks />
<main>{children}</main>
</body>
</html>
)
}
import { NavLinks } from '@/app/ui/nav-links'
export default function Layout({ children }) {
return (
<html lang="en">
<body>
<NavLinks />
<main>{children}</main>
</body>
</html>
)
}
params
に基づくコンテンツの表示
動的ルートセグメントを使用すると、params
プロップに基づいて特定のコンテンツを表示または取得できます。
export default async function DashboardLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ team: string }>
}) {
const { team } = await params
return (
<section>
<header>
<h1>{team}のダッシュボードへようこそ</h1>
</header>
<main>{children}</main>
</section>
)
}
export default async function DashboardLayout({ children, params }) {
const { team } = await params
return (
<section>
<header>
<h1>{team}のダッシュボードへようこそ</h1>
</header>
<main>{children}</main>
</section>
)
}
クライアントコンポーネントでの params
の読み取り
クライアントコンポーネント(async
にできない)で params
を使用するには、React の use
関数を使用してプロミスを読み取ることができます:
'use client'
import { use } from 'react'
export default function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = use(params)
}
'use client'
import { use } from 'react'
export default function Page({ params }) {
const { slug } = use(params)
}
バージョン履歴
バージョン | 変更内容 |
---|---|
v15.0.0-RC | params がプロミスになりました。コードモッドが利用可能です。 |
v13.0.0 | layout が導入されました。 |