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>
  )
}

リファレンス

プロパティ

children (必須)

レイアウトコンポーネントは children プロパティを受け取り、使用する必要があります。レンダリング時、children にはレイアウトがラップしているルートセグメントが含まれます。これには主に子の Layout(存在する場合)または Page のコンポーネントが含まれますが、状況によっては LoadingError などの特別なファイルも含まれる場合があります。

params (オプション)

ルートセグメントからそのレイアウトまでの 動的ルートパラメータ オブジェクトを含む Promise です。

export default async function Layout({
  params,
}: {
  params: Promise<{ team: string }>
}) {
  const { team } = await params
}
ルート例URLparams
app/dashboard/[team]/layout.js/dashboard/1Promise<{ team: '1' }>
app/shop/[tag]/[item]/layout.js/shop/1/2Promise<{ tag: '1', item: '2' }>
app/blog/[...slug]/layout.js/blog/1/2Promise<{ slug: ['1', '2'] }>
  • params プロパティは Promise です。値にアクセスするには async/await または React の use 関数を使用する必要があります。
    • バージョン 14 以前では、params は同期プロパティでした。後方互換性のために Next.js 15 でも同期的にアクセスできますが、この動作は将来非推奨になります。

ルートレイアウト

app ディレクトリには 必ず ルート app/layout.js を含める必要があります。

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}
  • ルートレイアウトは 必ず <html> タグと <body> タグを定義する必要があります。
    • <title><meta> などの <head> タグをルートレイアウトに手動で追加するべきではありません。代わりに、ストリーミングや <head> 要素の重複排除などの高度な要件を自動的に処理する Metadata API を使用してください。
  • ルートグループ を使用して複数のルートレイアウトを作成できます。
    • 複数のルートレイアウト間を移動 すると、フルページロード が発生します(クライアントサイドナビゲーションとは異なります)。例えば、app/(shop)/layout.js を使用する /cart から app/(marketing)/layout.js を使用する /blog に移動すると、フルページロードが発生します。これは 複数のルートレイアウトの場合のみ 適用されます。

注意点

リクエストオブジェクト

レイアウトはナビゲーション時にクライアント側でキャッシュされ、不要なサーバーリクエストを回避します。

レイアウト は再レンダリングされません。ページ間を移動する際に不要な計算を避けるためにキャッシュされ、再利用されます。レイアウトから生のリクエストにアクセスできないように制限することで、Next.js はレイアウト内でパフォーマンスに悪影響を与える可能性のある遅いまたは高コストなユーザーコードの実行を防ぎます。

リクエストオブジェクトにアクセスするには、Server Components および Functions で headerscookies 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 '...'
}

パス名

レイアウトはナビゲーション時に再レンダリングされないため、古くなる可能性のあるパス名にアクセスできません。

現在のパス名にアクセスするには、クライアントコンポーネント内で usePathname フックを使用して読み取ります。クライアントコンポーネントはナビゲーション時に再レンダリングされるため、最新のパス名にアクセスできます。

'use client'

import { usePathname } from 'next/navigation'

// 簡略化したパンくずリストロジック
export default function Breadcrumbs() {
  const pathname = usePathname()
  const segments = pathname.split('/')

  return (
    <nav>
      {segments.map((segment, index) => (
        <span key={index}>
          {' > '}
          {segment}
        </span>
      ))}
    </nav>
  )
}

データの取得

レイアウトは children にデータを渡すことができません。ただし、ルートで同じデータを複数回取得し、React の cache を使用してリクエストを重複排除してもパフォーマンスに影響を与えません。

あるいは、Next.js で fetch を使用すると、リクエストは自動的に重複排除されます。

export async function getUser(id: string) {
  const res = await fetch(`https://.../users/${id}`)
  return res.json()
}

子セグメントへのアクセス

レイアウトは自身より下のルートセグメントにアクセスできません。すべてのルートセグメントにアクセスするには、クライアントコンポーネントで 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}`}
      // リンクがアクティブかどうかに応じてスタイルを変更
      style={{ fontWeight: isActive ? 'bold' : 'normal' }}
    >
      {children}
    </Link>
  )
}

メタデータ

metadata オブジェクト または generateMetadata 関数 を使用して、titlemeta などの <head> HTML 要素を変更できます。

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> 要素の重複排除などの高度な要件を自動的に処理する Metadata 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>
  )
}

params に基づくコンテンツの表示

ダイナミックルートセグメントを使用すると、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 を使用するには、React の use 関数を使用してプロミスを読み取ることができます:

'use client'

import { use } from 'react'

export default function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = use(params)
}

バージョン履歴

バージョン変更内容
v15.0.0-RCparams がプロミスになりました。コードモッドが利用可能です。
v13.0.0layout が導入されました。