layout.js
Le fichier layout
est utilisé pour définir une mise en page (layout) dans votre application Next.js.
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}
export default function DashboardLayout({ children }) {
return <section>{children}</section>
}
Un layout racine est la mise en page la plus haute dans le répertoire racine app
. Il est utilisé pour définir les balises <html>
et <body>
ainsi que d'autres éléments d'interface utilisateur partagés globalement.
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>
)
}
Référence
Props
children
(requis)
Les composants de mise en page doivent accepter et utiliser une prop children
. Pendant le rendu, children
sera rempli avec les segments de route que le layout englobe. Il s'agira principalement du composant d'un Layout enfant (s'il existe) ou d'une Page, mais pourrait aussi être d'autres fichiers spéciaux comme Loading ou Error le cas échéant.
params
(optionnel)
Une promesse qui se résout en un objet contenant les paramètres de route dynamique depuis le segment racine jusqu'à ce layout.
export default async function Layout({
params,
}: {
params: Promise<{ team: string }>
}) {
const { team } = await params
}
export default async function Layout({ params }) {
const { team } = await params
}
Exemple de route | 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'] }> |
- Comme la prop
params
est une promesse, vous devez utiliserasync/await
ou la fonctionuse
de React pour accéder aux valeurs.- Dans la version 14 et antérieures,
params
était une prop synchrone. Pour assurer la compatibilité ascendante, vous pouvez toujours y accéder de manière synchrone dans Next.js 15, mais ce comportement sera déprécié à l'avenir.
- Dans la version 14 et antérieures,
Layout racine
Le répertoire app
doit inclure un app/layout.js
racine.
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>
)
}
- Le layout racine doit définir les balises
<html>
et<body>
.- Vous ne devriez pas ajouter manuellement des balises
<head>
comme<title>
et<meta>
aux layouts racines. Utilisez plutôt l'API Metadata qui gère automatiquement des exigences avancées comme le streaming et la déduplication des éléments<head>
.
- Vous ne devriez pas ajouter manuellement des balises
- Vous pouvez utiliser des groupes de routes pour créer plusieurs layouts racines.
- Naviguer entre plusieurs layouts racines provoquera un rechargement complet de la page (par opposition à une navigation côté client). Par exemple, naviguer de
/cart
qui utiliseapp/(shop)/layout.js
vers/blog
qui utiliseapp/(marketing)/layout.js
provoquera un rechargement complet. Cela s'applique uniquement aux multiples layouts racines.
- Naviguer entre plusieurs layouts racines provoquera un rechargement complet de la page (par opposition à une navigation côté client). Par exemple, naviguer de
Mises en garde
Objet Request
Les layouts sont mis en cache côté client pendant la navigation pour éviter des requêtes serveur inutiles.
Les Layouts ne sont pas rerendus. Ils peuvent être mis en cache et réutilisés pour éviter des calculs inutiles lors de la navigation entre pages. En restreignant l'accès des layouts à la requête brute, Next.js peut empêcher l'exécution de code utilisateur potentiellement lent ou coûteux dans le layout, ce qui pourrait nuire aux performances.
Pour accéder à l'objet request, vous pouvez utiliser les APIs headers
et cookies
dans les Composants Serveur et Fonctions.
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 '...'
}
Paramètres de requête
Les layouts ne sont pas rerendus lors de la navigation, donc ils ne peuvent pas accéder aux paramètres de recherche qui deviendraient obsolètes.
Pour accéder aux paramètres de requête mis à jour, vous pouvez utiliser la prop searchParams
de la Page, ou les lire dans un Composant Client en utilisant le hook useSearchParams
. Comme les Composants Clients sont rerendus lors de la navigation, ils ont accès aux derniers paramètres de requête.
'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}
</>
)
}
Pathname
Les layouts ne sont pas rerendus lors de la navigation, donc ils n'ont pas accès au pathname qui deviendrait obsolète.
Pour accéder au pathname actuel, vous pouvez le lire dans un Composant Client en utilisant le hook usePathname
. Comme les Composants Clients sont rerendus lors de la navigation, ils ont accès au dernier pathname.
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>
</>
)
}
Récupération de données
Les layouts ne peuvent pas transmettre de données à leurs children
. Cependant, vous pouvez récupérer les mêmes données plusieurs fois dans une route, et utiliser le cache
de React pour dédupliquer les requêtes sans affecter les performances.
Alternativement, lorsque vous utilisez fetch
dans Next.js, les requêtes sont automatiquement dédupliquées.
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>Bienvenue {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>Bienvenue {user.name}</h1>
</div>
)
}
Accès aux segments enfants
Les layouts n'ont pas accès aux segments de route en dessous d'eux-mêmes. Pour accéder à tous les segments de route, vous pouvez utiliser useSelectedLayoutSegment
ou useSelectedLayoutSegments
dans un Composant Client.
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>
)
}
Exemples
Métadonnées
Vous pouvez modifier les éléments HTML <head>
comme title
et meta
en utilisant l'objet metadata
ou la fonction generateMetadata
.
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 '...'
}
Bon à savoir : Vous ne devriez pas ajouter manuellement des balises
<head>
comme<title>
et<meta>
aux layouts racines. Utilisez plutôt les APIs Metadata qui gèrent automatiquement des exigences avancées comme le streaming et la déduplication des éléments<head>
.
Liens de navigation actifs
Vous pouvez utiliser le hook usePathname
pour déterminer si un lien de navigation est actif.
Comme usePathname
est un hook client, vous devez extraire les liens de navigation dans un Composant Client, qui peut être importé dans votre layout :
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>
)
}
Affichage de contenu basé sur les params
En utilisant les segments de route dynamiques, vous pouvez afficher ou récupérer du contenu spécifique en fonction de la prop params
.
export default async function DashboardLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ team: string }>
}) {
const { team } = await params
return (
<section>
<header>
<h1>Bienvenue sur le tableau de bord de {team}</h1>
</header>
<main>{children}</main>
</section>
)
}
export default async function DashboardLayout({ children, params }) {
const { team } = await params
return (
<section>
<header>
<h1>Bienvenue sur le tableau de bord de {team}</h1>
</header>
<main>{children}</main>
</section>
)
}
Lecture des params
dans les composants clients
Pour utiliser params
dans un composant client (qui ne peut pas être async
), vous pouvez utiliser la fonction use
de React pour lire la promesse :
'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)
}
Historique des versions
Version | Modifications |
---|---|
v15.0.0-RC | params est désormais une promesse. Un codemod est disponible. |
v13.0.0 | Introduction de layout . |