layout.js
layout ファイルは、Next.js アプリケーションでレイアウトを定義するために使用されます。
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}ルートレイアウトは、ルート app ディレクトリの一番上のレイアウトです。 <html> および <body> タグ、その他のグローバルに共有される UI を定義するために使用されます。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}リファレンス
Props
children(必須)
レイアウトコンポーネントは children プロップを受け入れて使用する必要があります。レンダリング中、children はレイアウトがラップしているルートセグメントで展開されます。これらは主に子 レイアウト(存在する場合)または ページ のコンポーネントになりますが、該当する場合は ローディング または エラー のような他の特別なファイルになることもあります。
params (オプション)
ルートセグメントからそのレイアウトまでの 動的ルートパラメータ オブジェクトを含むオブジェクトに解決される Promise。
export default async function Layout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ team: string }>
}) {
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 以前では、
レイアウトプロップヘルパー
LayoutProps でレイアウトを型付けすることで、ディレクトリ構造から推論される強力な型を持つ params および名前付きスロットを取得できます。 LayoutProps はグローバルに利用可能なヘルパーです。
export default function Layout(props: LayoutProps<'/dashboard'>) {
return (
<section>
{props.children}
{/* If you have app/dashboard/@analytics, it appears as a typed slot: */}
{/* {props.analytics} */}
</section>
)
}知っておくと良いこと:
- 型は
next dev、next build、またはnext typegenの実行中に生成されます。- 型生成後、
LayoutPropsヘルパーはグローバルに利用可能になります。インポートする必要はありません。
ルートレイアウト
app ディレクトリには、ルート app ディレクトリの一番上のレイアウトであるルートレイアウトを含める必要があります。通常、ルートレイアウトは app/layout.js です。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>{children}</body>
</html>
)
}- ルートレイアウトは、
<html>および<body>タグを定義する必要があります。- ルートレイアウトに
<title>や<meta>のような<head>タグを手動で追加しないでください。代わりに、ストリーミングや<head>要素の重複排除などの高度な要件を自動的に処理する メタデータAPI を使用する必要があります。
- ルートレイアウトに
- ルートグループを使用して、複数のルートレイアウトを作成できます。
- 複数のルートレイアウト間のナビゲーションは、フルページロード(クライアントサイドナビゲーションとは対照的)を引き起こします。たとえば、
app/(shop)/layout.jsを使用する/cartからapp/(marketing)/layout.jsを使用する/blogにナビゲートすると、フルページロードが発生します。これは複数のルートレイアウトにのみ適用されます。
- 複数のルートレイアウト間のナビゲーションは、フルページロード(クライアントサイドナビゲーションとは対照的)を引き起こします。たとえば、
- ルートレイアウトは動的セグメントの下に配置できます。たとえば、
app/[lang]/layout.jsを使用して国際化 国際化 を実装する場合などです。
注意点
リクエストオブジェクト
ナビゲーション中にレイアウトはクライアント側でキャッシュされるため、不要なサーバーリクエストが回避されます。
レイアウトは再レンダリングされません。ページ間のナビゲーション時に不要な計算を回避するためにキャッシュして再利用できます。レイアウトが生の要求にアクセスできないように制限することで、Next.js はレイアウト内で潜在的に遅い、またはコストのかかるユーザーコードの実行を防ぐことができ、パフォーマンスへの悪影響を軽減できます。
リクエストオブジェクトにアクセスするには、サーバーコンポーネントおよび関数で headers API および cookies API を使用できます。
import { cookies } from 'next/headers'
export default async function Layout({ children }) {
const cookieStore = await cookies()
const theme = cookieStore.get('theme')
return '...'
}クエリパラメータ
レイアウトはナビゲーション時に再レンダリングされないため、古い値になる可能性のある検索パラメータにアクセスできません。
更新されたクエリパラメータにアクセスするには、Page の searchParams プロップを使用するか、クライアントコンポーネント内で useSearchParams フックを使用して読み取ることができます。クライアントコンポーネントはナビゲーション時に再レンダリングされるため、最新のクエリパラメータにアクセスできます。
'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}
</>
)
}パス名
レイアウトはナビゲーション時に再レンダリングされないため、古い値になる可能性のあるパス名にアクセスできません。
現在のパス名にアクセスするには、クライアントコンポーネント内で usePathname フックを使用して読み取ることができます。クライアントコンポーネントはナビゲーション中に再レンダリングされるため、最新のパス名にアクセスできます。
'use client'
import { usePathname } from 'next/navigation'
// Simplified breadcrumbs logic
export default function Breadcrumbs() {
const pathname = usePathname()
const segments = pathname.split('/')
return (
<nav>
{segments.map((segment, index) => (
<span key={index}>
{' > '}
{segment}
</span>
))}
</nav>
)
}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 Page() {
const user = await getUser('1')
return (
<div>
<h1>Welcome {user.name}</h1>
</div>
)
}子セグメントへのアクセス
レイアウトは、その下のルートセグメントにアクセスできません。すべてのルートセグメントにアクセスするには、クライアントコンポーネントで useSelectedLayoutSegment または useSelectedLayoutSegments を使用できます。
'use client'
import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'
export default function NavLink({
slug,
children,
}: {
slug: string
children: React.ReactNode
}) {
const segment = useSelectedLayoutSegment()
const isActive = slug === segment
return (
<Link
href={`/blog/${slug}`}
// Change style depending on whether the link is active
style={{ fontWeight: isActive ? 'bold' : 'normal' }}
>
{children}
</Link>
)
}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>
)
}例
Metadata
title および meta のような <head> HTML 要素は、metadata オブジェクト または generateMetadata 関数 を使用して変更できます。
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Next.js',
}
export default function Layout({ children }: { children: React.ReactNode }) {
return '...'
}知っておくと良いこと: ルートレイアウトに
<title>や<meta>のような<head>タグを手動で追加しないでください。代わりに、ストリーミングや<head>要素の重複排除などの高度な要件を自動的に処理する メタデータAPI を使用してください。
アクティブなナビゲーションリンク
ナビゲーションリンクがアクティブかどうかを判断するために usePathname フックを使用できます。
usePathname はクライアントフックであるため、ナビゲーションリンクをクライアントコンポーネントに抽出する必要があります。これはレイアウトにインポートできます。
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function NavLinks() {
const pathname = usePathname()
return (
<nav>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Home
</Link>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
About
</Link>
</nav>
)
}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>
)
}params に基づくコンテンツの表示
dynamic route segments を使用して、params プロップに基づいて特定のコンテンツを表示または取得できます。
export default async function DashboardLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ team: string }>
}) {
const { team } = await params
return (
<section>
<header>
<h1>Welcome to {team}'s Dashboard</h1>
</header>
<main>{children}</main>
</section>
)
}クライアントコンポーネントでの params の読み取り
クライアントコンポーネント(async にできない)で params を使用するには、Promise を読み取るために React の use 関数を使用できます。
'use client'
import { use } from 'react'
export default function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = use(params)
}バージョン履歴
| バージョン | 変更履歴 |
|---|---|
v15.0.0-RC | params は Promise になりました。 コードモッド が利用可能です。 |
v13.0.0 | layout が導入されました。 |
役に立ちましたか?