Guide d'adoption progressive du routeur App
Ce guide vous aidera à :
- Mettre à jour votre application Next.js de la version 12 à la version 13
- Améliorer les fonctionnalités qui fonctionnent à la fois dans les répertoires
pages
etapp
- Migrer progressivement votre application existante de
pages
versapp
Mise à niveau
Version de Node.js
La version minimale de Node.js est désormais v18.17. Consultez la documentation de Node.js pour plus d'informations.
Version de Next.js
Pour mettre à jour vers Next.js version 13, exécutez la commande suivante avec votre gestionnaire de paquets préféré :
npm install next@latest react@latest react-dom@latest
Version d'ESLint
Si vous utilisez ESLint, vous devez mettre à jour votre version d'ESLint :
npm install -D eslint-config-next@latest
Bon à savoir : Vous devrez peut-être redémarrer le serveur ESLint dans VS Code pour que les modifications d'ESLint prennent effet. Ouvrez la palette de commandes (
cmd+shift+p
sur Mac ;ctrl+shift+p
sur Windows) et recherchezESLint: Restart ESLint Server
.
Prochaines étapes
Après la mise à jour, consultez les sections suivantes pour les prochaines étapes :
- Améliorer les nouvelles fonctionnalités : Un guide pour vous aider à migrer vers les nouvelles fonctionnalités telles que les composants Image et Link améliorés.
- Migrer du répertoire
pages
versapp
: Un guide étape par étape pour vous aider à migrer progressivement du répertoirepages
versapp
.
Amélioration des nouvelles fonctionnalités
Next.js 13 a introduit le nouveau routeur App avec de nouvelles fonctionnalités et conventions. Le nouveau routeur est disponible dans le répertoire app
et coexiste avec le répertoire pages
.
La mise à niveau vers Next.js 13 ne nécessite pas l'utilisation du nouveau routeur App. Vous pouvez continuer à utiliser pages
avec les nouvelles fonctionnalités qui fonctionnent dans les deux répertoires, comme le composant Image mis à jour, le composant Link, le composant Script et l'optimisation des polices.
Composant <Image/>
Next.js 12 a introduit des améliorations pour le composant Image avec une importation temporaire : next/future/image
. Ces améliorations incluaient moins de JavaScript côté client, des moyens plus simples d'étendre et de styliser les images, une meilleure accessibilité et un chargement paresseux natif du navigateur.
Dans la version 13, ce nouveau comportement est désormais celui par défaut pour next/image
.
Il existe deux codemods pour vous aider à migrer vers le nouveau composant Image :
- Codemod
next-image-to-legacy-image
: Renomme automatiquement et en toute sécurité les importsnext/image
ennext/legacy/image
. Les composants existants conserveront le même comportement. - Codemod
next-image-experimental
: Ajoute de manière risquée des styles en ligne et supprime les props inutilisés. Cela changera le comportement des composants existants pour correspondre aux nouveaux paramètres par défaut. Pour utiliser ce codemod, vous devez d'abord exécuter le codemodnext-image-to-legacy-image
.
Composant <Link>
Le composant <Link>
ne nécessite plus d'ajouter manuellement une balise <a>
comme enfant. Ce comportement a été ajouté comme option expérimentale dans la version 12.2 et est maintenant celui par défaut. Dans Next.js 13, <Link>
rend toujours <a>
et vous permet de transmettre des props à la balise sous-jacente.
Par exemple :
import Link from 'next/link'
// Next.js 12 : `<a>` doit être imbriqué sinon il est exclu
<Link href="/about">
<a>About</a>
</Link>
// Next.js 13 : `<Link>` rend toujours `<a>` en arrière-plan
<Link href="/about">
About
</Link>
Pour mettre à niveau vos liens vers Next.js 13, vous pouvez utiliser le codemod new-link
.
Composant <Script>
Le comportement de next/script
a été mis à jour pour prendre en charge à la fois pages
et app
, mais certaines modifications doivent être apportées pour assurer une migration fluide :
- Déplacez tous les scripts
beforeInteractive
que vous avez précédemment inclus dans_document.js
vers le fichier de disposition racine (app/layout.tsx
). - La stratégie expérimentale
worker
ne fonctionne pas encore dansapp
et les scripts désignés avec cette stratégie devront être supprimés ou modifiés pour utiliser une autre stratégie (par exemplelazyOnload
). - Les gestionnaires
onLoad
,onReady
etonError
ne fonctionneront pas dans les composants serveur, assurez-vous donc de les déplacer vers un composant client ou de les supprimer complètement.
Optimisation des polices
Auparavant, Next.js vous aidait à optimiser les polices en inlinant le CSS des polices. La version 13 introduit le nouveau module next/font
qui vous donne la possibilité de personnaliser votre expérience de chargement des polices tout en garantissant des performances et une confidentialité optimales. next/font
est pris en charge à la fois dans les répertoires pages
et app
.
Bien que l'inlining CSS fonctionne toujours dans pages
, il ne fonctionne pas dans app
. Vous devez utiliser next/font
à la place.
Consultez la page Optimisation des polices pour apprendre à utiliser next/font
.
Migration de pages
vers app
🎥 Regardez : Apprenez à adopter progressivement le routeur App → YouTube (16 minutes).
Passer au routeur App peut être la première fois que vous utilisez des fonctionnalités React sur lesquelles Next.js s'appuie, telles que les composants serveur, Suspense, etc. Combinées avec les nouvelles fonctionnalités de Next.js telles que les fichiers spéciaux et les dispositions, la migration implique de nouveaux concepts, modèles mentaux et changements de comportement à apprendre.
Nous recommandons de réduire la complexité combinée de ces mises à jour en divisant votre migration en étapes plus petites. Le répertoire app
est conçu intentionnellement pour fonctionner simultanément avec le répertoire pages
afin de permettre une migration page par page progressive.
- Le répertoire
app
prend en charge les routes imbriquées et les dispositions. En savoir plus. - Utilisez des dossiers imbriqués pour définir des routes et un fichier spécial
page.js
pour rendre un segment de route accessible publiquement. En savoir plus. - Les conventions de fichiers spéciaux sont utilisées pour créer l'interface utilisateur de chaque segment de route. Les fichiers spéciaux les plus courants sont
page.js
etlayout.js
.- Utilisez
page.js
pour définir une interface utilisateur unique à une route. - Utilisez
layout.js
pour définir une interface utilisateur partagée entre plusieurs routes. - Les extensions de fichiers
.js
,.jsx
ou.tsx
peuvent être utilisées pour les fichiers spéciaux.
- Utilisez
- Vous pouvez colocaliser d'autres fichiers dans le répertoire
app
tels que des composants, des styles, des tests, etc. En savoir plus. - Les fonctions de récupération de données comme
getServerSideProps
etgetStaticProps
ont été remplacées par une nouvelle API dansapp
.getStaticPaths
a été remplacé pargenerateStaticParams
. pages/_app.js
etpages/_document.js
ont été remplacés par une seule disposition racineapp/layout.js
. En savoir plus.pages/_error.js
a été remplacé par des fichiers spéciauxerror.js
plus granulaires. En savoir plus.pages/404.js
a été remplacé par le fichiernot-found.js
.- Les routes API
pages/api/*
ont été remplacées par le fichier spécialroute.js
(gestionnaire de route).
Étape 1 : Création du répertoire app
Mettez à jour vers la dernière version de Next.js (nécessite la version 13.4 ou supérieure) :
npm install next@latest
Ensuite, créez un nouveau répertoire app
à la racine de votre projet (ou dans le répertoire src/
).
Étape 2 : Création d'une disposition racine
Créez un nouveau fichier app/layout.tsx
dans le répertoire app
. Il s'agit d'une disposition racine qui s'appliquera à toutes les routes dans app
.
export default function RootLayout({
// Les dispositions doivent accepter une prop children.
// Ce sera rempli avec des dispositions ou des pages imbriquées
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
export default function RootLayout({
// Les dispositions doivent accepter une prop children.
// Ce sera rempli avec des dispositions ou des pages imbriquées
children,
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
- Le répertoire
app
doit inclure une disposition racine. - La disposition racine doit définir les balises
<html>
et<body>
car Next.js ne les crée pas automatiquement. - La disposition racine remplace les fichiers
pages/_app.tsx
etpages/_document.tsx
. - Les extensions
.js
,.jsx
ou.tsx
peuvent être utilisées pour les fichiers de disposition.
Pour gérer les éléments HTML <head>
, vous pouvez utiliser la prise en charge SEO intégrée :
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Accueil',
description: 'Bienvenue sur Next.js',
}
export const metadata = {
title: 'Accueil',
description: 'Bienvenue sur Next.js',
}
Migration de _document.js
et _app.js
Si vous avez un fichier _app
ou _document
existant, vous pouvez copier son contenu (par exemple, les styles globaux) dans la disposition racine (app/layout.tsx
). Les styles dans app/layout.tsx
ne s'appliqueront pas à pages/*
. Vous devez conserver _app
/_document
pendant la migration pour éviter que vos routes pages/*
ne cessent de fonctionner. Une fois la migration terminée, vous pouvez les supprimer en toute sécurité.
Si vous utilisez des fournisseurs de contexte React, ils devront être déplacés vers un composant client.
Migration du modèle getLayout()
vers les dispositions (Optionnel)
Next.js recommandait d'ajouter une propriété aux composants Page pour obtenir des dispositions par page dans le répertoire pages
. Ce modèle peut être remplacé par la prise en charge native des dispositions imbriquées dans le répertoire app
.
Voir un exemple avant/après
Avant
export default function DashboardLayout({ children }) {
return (
<div>
<h2>Mon tableau de bord</h2>
{children}
</div>
)
}
import DashboardLayout from '../components/DashboardLayout'
export default function Page() {
return <p>Ma page</p>
}
Page.getLayout = function getLayout(page) {
return <DashboardLayout>{page}</DashboardLayout>
}
Après
-
Supprimez la propriété
Page.getLayout
depages/dashboard/index.js
et suivez les étapes pour migrer les pages vers le répertoireapp
.app/dashboard/page.js export default function Page() { return <p>Ma page</p> }
-
Déplacez le contenu de
DashboardLayout
dans un nouveau composant client pour conserver le comportement du répertoirepages
.app/dashboard/DashboardLayout.js 'use client' // cette directive doit être en haut du fichier, avant toute importation. // Ceci est un composant client export default function DashboardLayout({ children }) { return ( <div> <h2>Mon tableau de bord</h2> {children} </div> ) }
-
Importez
DashboardLayout
dans un nouveau fichierlayout.js
dans le répertoireapp
.app/dashboard/layout.js import DashboardLayout from './DashboardLayout' // Ceci est un composant serveur export default function Layout({ children }) { return <DashboardLayout>{children}</DashboardLayout> }
-
Vous pouvez déplacer progressivement les parties non interactives de
DashboardLayout.js
(composant client) danslayout.js
(composant serveur) pour réduire la quantité de JavaScript de composant envoyé au client.
Étape 3 : Migration de next/head
Dans le répertoire pages
, le composant React next/head
est utilisé pour gérer les éléments HTML <head>
tels que title
et meta
. Dans le répertoire app
, next/head
est remplacé par la nouvelle prise en charge SEO intégrée.
Avant :
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>Titre de ma page</title>
</Head>
</>
)
}
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>Titre de ma page</title>
</Head>
</>
)
}
Après :
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Titre de ma page',
}
export default function Page() {
return '...'
}
export const metadata = {
title: 'Titre de ma page',
}
export default function Page() {
return '...'
}
Voir toutes les options de métadonnées.
Étape 4 : Migration des pages
- Les pages dans le répertoire
app
sont par défaut des composants serveur (Server Components). Ceci diffère du répertoirepages
où les pages sont des composants client (Client Components). - La récupération de données (Data fetching) a changé dans
app
.getServerSideProps
,getStaticProps
etgetInitialProps
ont été remplacés par une API plus simple. - Le répertoire
app
utilise des dossiers imbriqués pour définir les routes (defining routes) et un fichier spécialpage.js
pour rendre un segment de route accessible publiquement. -
Répertoire pages
Répertoire app
Route index.js
page.js
/
about.js
about/page.js
/about
blog/[slug].js
blog/[slug]/page.js
/blog/post-1
Nous recommandons de diviser la migration d'une page en deux étapes principales :
- Étape 1 : Déplacer le composant Page exporté par défaut dans un nouveau composant client.
- Étape 2 : Importer le nouveau composant client dans un fichier
page.js
à l'intérieur du répertoireapp
.
Bon à savoir : C'est le chemin de migration le plus simple car il offre le comportement le plus comparable au répertoire
pages
.
Étape 1 : Créer un nouveau composant client
- Créez un nouveau fichier séparé dans le répertoire
app
(par exempleapp/home-page.tsx
ou similaire) qui exporte un composant client. Pour définir des composants client, ajoutez la directive'use client'
en haut du fichier (avant toute importation).- Comme avec le routeur Pages, il y a une étape d'optimisation pour prérendre les composants client en HTML statique lors du chargement initial de la page.
- Déplacez le composant de page exporté par défaut de
pages/index.js
versapp/home-page.tsx
.
'use client'
// Ceci est un composant client (identique aux composants du répertoire `pages`)
// Il reçoit des données via des props, a accès à l'état et aux effets, et est
// prérendu sur le serveur lors du chargement initial de la page.
export default function HomePage({ recentPosts }) {
return (
<div>
{recentPosts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
'use client'
// Ceci est un composant client. Il reçoit des données via des props et
// a accès à l'état et aux effets, tout comme les composants Page
// dans le répertoire `pages`.
export default function HomePage({ recentPosts }) {
return (
<div>
{recentPosts.map((post) => (
<div key={post.id}>{post.title}</div>
))}
</div>
)
}
Étape 2 : Créer une nouvelle page
-
Créez un nouveau fichier
app/page.tsx
dans le répertoireapp
. Ceci est par défaut un composant serveur. -
Importez le composant client
home-page.tsx
dans la page. -
Si vous récupériez des données dans
pages/index.js
, déplacez la logique de récupération de données directement dans le composant serveur en utilisant les nouvelles API de récupération de données (data fetching APIs). Consultez le guide de mise à niveau pour la récupération de données pour plus de détails.// Importez votre composant client import HomePage from './home-page' async function getPosts() { const res = await fetch('https://...') const posts = await res.json() return posts } export default async function Page() { // Récupérez les données directement dans un composant serveur const recentPosts = await getPosts() // Transmettez les données récupérées à votre composant client return <HomePage recentPosts={recentPosts} /> }
// Importez votre composant client import HomePage from './home-page' async function getPosts() { const res = await fetch('https://...') const posts = await res.json() return posts } export default async function Page() { // Récupérez les données directement dans un composant serveur const recentPosts = await getPosts() // Transmettez les données récupérées à votre composant client return <HomePage recentPosts={recentPosts} /> }
-
Si votre page précédente utilisait
useRouter
, vous devrez passer aux nouveaux hooks de routage. En savoir plus. -
Démarrez votre serveur de développement et visitez
http://localhost:3000
. Vous devriez voir votre route d'index existante, maintenant servie via le répertoire app.
Étape 5 : Migration des hooks de routage
Un nouveau routeur a été ajouté pour prendre en charge le nouveau comportement dans le répertoire app
.
Dans app
, vous devez utiliser les trois nouveaux hooks importés depuis next/navigation
: useRouter()
, usePathname()
et useSearchParams()
.
- Le nouveau hook
useRouter
est importé depuisnext/navigation
et a un comportement différent du hookuseRouter
danspages
qui est importé depuisnext/router
.- Le hook
useRouter
importé depuisnext/router
n'est pas pris en charge dans le répertoireapp
mais peut continuer à être utilisé dans le répertoirepages
.
- Le hook
- Le nouveau
useRouter
ne renvoie pas la chaînepathname
. Utilisez plutôt le hook séparéusePathname
. - Le nouveau
useRouter
ne renvoie pas l'objetquery
. Utilisez plutôt le hook séparéuseSearchParams
. - Vous pouvez utiliser
useSearchParams
etusePathname
ensemble pour écouter les changements de page. Consultez la section Événements du routeur (Router Events) pour plus de détails. - Ces nouveaux hooks ne sont pris en charge que dans les composants client. Ils ne peuvent pas être utilisés dans les composants serveur.
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
export default function ExampleClientComponent() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
// ...
}
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
export default function ExampleClientComponent() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
// ...
}
De plus, le nouveau hook useRouter
présente les changements suivants :
isFallback
a été supprimé carfallback
a été remplacé.- Les valeurs
locale
,locales
,defaultLocales
,domainLocales
ont été supprimées car les fonctionnalités i18n intégrées de Next.js ne sont plus nécessaires dans le répertoireapp
. En savoir plus sur i18n. basePath
a été supprimé. L'alternative ne fera pas partie deuseRouter
. Elle n'a pas encore été implémentée.asPath
a été supprimé car le concept deas
a été retiré du nouveau routeur.isReady
a été supprimé car il n'est plus nécessaire. Pendant le rendu statique (static rendering), tout composant qui utilise le hookuseSearchParams()
sautera l'étape de prérendu et sera plutôt rendu côté client au moment de l'exécution.
Voir la référence API de useRouter()
.
Étape 6 : Migration des méthodes de récupération de données
Le répertoire pages
utilise getServerSideProps
et getStaticProps
pour récupérer des données pour les pages. Dans le répertoire app
, ces anciennes fonctions de récupération de données sont remplacées par une API plus simple basée sur fetch()
et les composants serveur React asynchrones.
export default async function Page() {
// Cette requête doit être mise en cache jusqu'à invalidation manuelle.
// Similaire à `getStaticProps`.
// `force-cache` est la valeur par défaut et peut être omis.
const staticData = await fetch(`https://...`, { cache: 'force-cache' })
// Cette requête doit être récupérée à chaque requête.
// Similaire à `getServerSideProps`.
const dynamicData = await fetch(`https://...`, { cache: 'no-store' })
// Cette requête doit être mise en cache avec une durée de vie de 10 secondes.
// Similaire à `getStaticProps` avec l'option `revalidate`.
const revalidatedData = await fetch(`https://...`, {
next: { revalidate: 10 },
})
return <div>...</div>
}
export default async function Page() {
// Cette requête doit être mise en cache jusqu'à invalidation manuelle.
// Similaire à `getStaticProps`.
// `force-cache` est la valeur par défaut et peut être omis.
const staticData = await fetch(`https://...`, { cache: 'force-cache' })
// Cette requête doit être récupérée à chaque requête.
// Similaire à `getServerSideProps`.
const dynamicData = await fetch(`https://...`, { cache: 'no-store' })
// Cette requête doit être mise en cache avec une durée de vie de 10 secondes.
// Similaire à `getStaticProps` avec l'option `revalidate`.
const revalidatedData = await fetch(`https://...`, {
next: { revalidate: 10 },
})
return <div>...</div>
}
Rendu côté serveur (getServerSideProps
)
Dans le répertoire pages
, getServerSideProps
est utilisé pour récupérer des données côté serveur et transmettre des props au composant React exporté par défaut dans le fichier. Le HTML initial pour la page est prérendu depuis le serveur, suivi par "l'hydratation" de la page dans le navigateur (la rendant interactive).
// Répertoire `pages`
export async function getServerSideProps() {
const res = await fetch(`https://...`)
const projects = await res.json()
return { props: { projects } }
}
export default function Dashboard({ projects }) {
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
Dans le répertoire app
, nous pouvons colocaliser notre récupération de données à l'intérieur de nos composants React en utilisant des composants serveur (Server Components). Cela nous permet d'envoyer moins de JavaScript au client, tout en conservant le HTML rendu depuis le serveur.
En définissant l'option cache
à no-store
, nous pouvons indiquer que les données récupérées ne doivent jamais être mises en cache. Ceci est similaire à getServerSideProps
dans le répertoire pages
.
// Répertoire `app`
// Cette fonction peut avoir n'importe quel nom
async function getProjects() {
const res = await fetch(`https://...`, { cache: 'no-store' })
const projects = await res.json()
return projects
}
export default async function Dashboard() {
const projects = await getProjects()
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
// Répertoire `app`
// Cette fonction peut avoir n'importe quel nom
async function getProjects() {
const res = await fetch(`https://...`, { cache: 'no-store' })
const projects = await res.json()
return projects
}
export default async function Dashboard() {
const projects = await getProjects()
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
Accès à l'objet Request
Dans le répertoire pages
, vous pouvez récupérer des données basées sur la requête en utilisant l'API HTTP de Node.js.
Par exemple, vous pouvez récupérer l'objet req
depuis getServerSideProps
et l'utiliser pour récupérer les cookies et en-têtes de la requête.
// Répertoire `pages`
export async function getServerSideProps({ req, query }) {
const authHeader = req.getHeaders()['authorization'];
const theme = req.cookies['theme'];
return { props: { ... }}
}
export default function Page(props) {
return ...
}
Le répertoire app
expose de nouvelles fonctions en lecture seule pour récupérer les données de la requête :
headers()
: Basée sur l'API Web Headers, et peut être utilisée dans les composants serveur (Server Components) pour récupérer les en-têtes de la requête.cookies()
: Basée sur l'API Web Cookies, et peut être utilisée dans les composants serveur (Server Components) pour récupérer les cookies.
// Répertoire `app`
import { cookies, headers } from 'next/headers'
async function getData() {
const authHeader = headers().get('authorization')
return '...'
}
export default async function Page() {
// Vous pouvez utiliser `cookies()` ou `headers()` directement dans les composants serveur
// ou dans votre fonction de récupération de données
const theme = cookies().get('theme')
const data = await getData()
return '...'
}
// Répertoire `app`
import { cookies, headers } from 'next/headers'
async function getData() {
const authHeader = headers().get('authorization')
return '...'
}
export default async function Page() {
// Vous pouvez utiliser `cookies()` ou `headers()` directement dans les composants serveur
// ou dans votre fonction de récupération de données
const theme = cookies().get('theme')
const data = await getData()
return '...'
}
Génération de site statique (getStaticProps
)
Dans le répertoire pages
, la fonction getStaticProps
est utilisée pour prérendre une page au moment de la construction. Cette fonction peut être utilisée pour récupérer des données depuis une API externe ou directement depuis une base de données, et transmettre ces données à l'ensemble de la page pendant sa génération lors de la construction.
// Répertoire `pages`
export async function getStaticProps() {
const res = await fetch(`https://...`)
const projects = await res.json()
return { props: { projects } }
}
export default function Index({ projects }) {
return projects.map((project) => <div>{project.name}</div>)
}
Dans le répertoire app
, la récupération de données avec fetch()
utilisera par défaut cache: 'force-cache'
, ce qui mettra en cache les données de la requête jusqu'à invalidation manuelle. Ceci est similaire à getStaticProps
dans le répertoire pages
.
// Répertoire `app`
// Cette fonction peut avoir n'importe quel nom
async function getProjects() {
const res = await fetch(`https://...`)
const projects = await res.json()
return projects
}
export default async function Index() {
const projects = await getProjects()
return projects.map((project) => <div>{project.name}</div>)
}
Chemins dynamiques (getStaticPaths
)
Dans le répertoire pages
, la fonction getStaticPaths
est utilisée pour définir les chemins dynamiques qui doivent être pré-rendus au moment de la construction.
// Répertoire `pages`
import PostLayout from '@/components/post-layout'
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
}
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return { props: { post } }
}
export default function Post({ post }) {
return <PostLayout post={post} />
}
Dans le répertoire app
, getStaticPaths
est remplacé par generateStaticParams
.
generateStaticParams
se comporte de manière similaire à getStaticPaths
, mais propose une API simplifiée pour retourner les paramètres de route et peut être utilisée à l'intérieur des layouts. La forme de retour de generateStaticParams
est un tableau de segments au lieu d'un tableau d'objets param
imbriqués ou d'une chaîne de chemins résolus.
// Répertoire `app`
import PostLayout from '@/components/post-layout'
export async function generateStaticParams() {
return [{ id: '1' }, { id: '2' }]
}
async function getPost(params) {
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
return post
}
export default async function Post({ params }) {
const post = await getPost(params)
return <PostLayout post={post} />
}
L'utilisation du nom generateStaticParams
est plus appropriée que getStaticPaths
pour le nouveau modèle dans le répertoire app
. Le préfixe get
est remplacé par generate
, plus descriptif, qui se suffit mieux maintenant que getStaticProps
et getServerSideProps
ne sont plus nécessaires. Le suffixe Paths
est remplacé par Params
, plus adapté au routage imbriqué avec plusieurs segments dynamiques.
Remplacer fallback
Dans le répertoire pages
, la propriété fallback
retournée par getStaticPaths
est utilisée pour définir le comportement d'une page qui n'est pas pré-rendue au moment de la construction. Cette propriété peut être définie à true
pour afficher une page de secours pendant que la page est générée, false
pour afficher une page 404, ou blocking
pour générer la page au moment de la requête.
// Répertoire `pages`
export async function getStaticPaths() {
return {
paths: [],
fallback: 'blocking'
};
}
export async function getStaticProps({ params }) {
...
}
export default function Post({ post }) {
return ...
}
Dans le répertoire app
, la propriété config.dynamicParams
contrôle la gestion des paramètres non inclus dans generateStaticParams
:
true
: (par défaut) Les segments dynamiques non inclus dansgenerateStaticParams
sont générés à la demande.false
: Les segments dynamiques non inclus dansgenerateStaticParams
retourneront une 404.
Cela remplace l'option fallback: true | false | 'blocking'
de getStaticPaths
dans le répertoire pages
. L'option fallback: 'blocking'
n'est pas incluse dans dynamicParams
car la différence entre 'blocking'
et true
est négligeable avec le streaming.
// Répertoire `app`
export const dynamicParams = true;
export async function generateStaticParams() {
return [...]
}
async function getPost(params) {
...
}
export default async function Post({ params }) {
const post = await getPost(params);
return ...
}
Avec dynamicParams
défini à true
(par défaut), lorsqu'un segment de route est demandé et n'a pas été généré, il sera rendu côté serveur et mis en cache.
Régénération statique incrémentale (getStaticProps
avec revalidate
)
Dans le répertoire pages
, la fonction getStaticProps
permet d'ajouter un champ revalidate
pour régénérer automatiquement une page après un certain temps.
// Répertoire `pages`
export async function getStaticProps() {
const res = await fetch(`https://.../posts`)
const posts = await res.json()
return {
props: { posts },
revalidate: 60,
}
}
export default function Index({ posts }) {
return (
<Layout>
<PostList posts={posts} />
</Layout>
)
}
Dans le répertoire app
, la récupération de données avec fetch()
peut utiliser revalidate
, qui mettra en cache la requête pour le nombre de secondes spécifié.
// Répertoire `app`
async function getPosts() {
const res = await fetch(`https://.../posts`, { next: { revalidate: 60 } })
const data = await res.json()
return data.posts
}
export default async function PostList() {
const posts = await getPosts()
return posts.map((post) => <div>{post.name}</div>)
}
Routes API
Les routes API continuent de fonctionner dans le répertoire pages/api
sans aucun changement. Cependant, elles ont été remplacées par les Route Handlers dans le répertoire app
.
Les Route Handlers permettent de créer des gestionnaires de requêtes personnalisés pour une route donnée en utilisant les APIs Web Request et Response.
export async function GET(request: Request) {}
export async function GET(request) {}
Bon à savoir : Si vous utilisiez auparavant les routes API pour appeler une API externe depuis le client, vous pouvez maintenant utiliser les Composants Serveur pour récupérer des données de manière sécurisée. En savoir plus sur la récupération de données.
Étape 7 : Stylisation
Dans le répertoire pages
, les feuilles de style globales étaient limitées à pages/_app.js
. Avec le répertoire app
, cette restriction a été levée. Les styles globaux peuvent être ajoutés à n'importe quel layout, page ou composant.
Tailwind CSS
Si vous utilisez Tailwind CSS, vous devez ajouter le répertoire app
à votre fichier tailwind.config.js
:
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}', // <-- Ajoutez cette ligne
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
],
}
Vous devez également importer vos styles globaux dans votre fichier app/layout.js
:
import '../styles/globals.css'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
En savoir plus sur la stylisation avec Tailwind CSS
Codemods
Next.js fournit des transformations Codemod pour aider à mettre à jour votre codebase lorsqu'une fonctionnalité est dépréciée. Voir Codemods pour plus d'informations.