Pages et Mises en page (Layouts)
Le routeur Pages est basé sur un système de routage par système de fichiers, fondé sur le concept de pages.
Lorsqu'un fichier est ajouté au répertoire pages
, il devient automatiquement disponible en tant que route.
Dans Next.js, une page est un composant React exporté depuis un fichier .js
, .jsx
, .ts
, ou .tsx
dans le répertoire pages
. Chaque page est associée à une route en fonction de son nom de fichier.
Exemple : Si vous créez pages/about.js
qui exporte un composant React comme ci-dessous, il sera accessible à l'adresse /about
.
export default function About() {
return <div>About</div>
}
Routes d'index
Le routeur dirigera automatiquement les fichiers nommés index
vers la racine du répertoire.
pages/index.js
→/
pages/blog/index.js
→/blog
Routes imbriquées
Le routeur prend en charge les fichiers imbriqués. Si vous créez une structure de dossiers imbriquée, les fichiers seront automatiquement routés de la même manière.
pages/blog/first-post.js
→/blog/first-post
pages/dashboard/settings/username.js
→/dashboard/settings/username
Pages avec routes dynamiques
Next.js prend en charge les pages avec des routes dynamiques. Par exemple, si vous créez un fichier appelé pages/posts/[id].js
, il sera accessible aux adresses posts/1
, posts/2
, etc.
Pour en savoir plus sur le routage dynamique, consultez la documentation sur le routage dynamique.
Modèle de mise en page (Layout)
Le modèle React nous permet de décomposer une page en une série de composants. Beaucoup de ces composants sont souvent réutilisés entre les pages. Par exemple, vous pourriez avoir la même barre de navigation et le même pied de page sur chaque page.
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
Exemples
Mise en page unique partagée avec une application personnalisée
Si vous n'avez qu'une seule mise en page pour toute votre application, vous pouvez créer une application personnalisée et envelopper votre application avec la mise en page. Comme le composant <Layout />
est réutilisé lors du changement de page, son état sera préservé (par exemple, les valeurs des champs de saisie).
import Layout from '../components/layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
Mises en page par page
Si vous avez besoin de plusieurs mises en page, vous pouvez ajouter une propriété getLayout
à votre page, ce qui vous permet de retourner un composant React pour la mise en page. Cela vous permet de définir la mise en page par page. Comme nous retournons une fonction, nous pouvons avoir des mises en page imbriquées complexes si nécessaire.
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return (
/** Votre contenu */
)
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default function MyApp({ Component, pageProps }) {
// Utilise la mise en page définie au niveau de la page, si disponible
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Lors de la navigation entre les pages, nous voulons conserver l'état de la page (valeurs des champs, position de défilement, etc.) pour une expérience d'application monopage (SPA).
Ce modèle de mise en page permet la persistance de l'état car l'arborescence des composants React est maintenue entre les transitions de page. Avec l'arborescence des composants, React peut comprendre quels éléments ont changé pour préserver l'état.
Bon à savoir : Ce processus s'appelle la réconciliation, qui est la façon dont React comprend quels éléments ont changé.
Avec TypeScript
Lorsque vous utilisez TypeScript, vous devez d'abord créer un nouveau type pour vos pages qui inclut une fonction getLayout
. Ensuite, vous devez créer un nouveau type pour vos AppProps
qui remplace la propriété Component
pour utiliser le type précédemment créé.
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'
const Page: NextPageWithLayout = () => {
return <p>hello world</p>
}
Page.getLayout = function getLayout(page: ReactElement) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default Page
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
const Page = () => {
return <p>hello world</p>
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default Page
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode
}
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout
}
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
// Utilise la mise en page définie au niveau de la page, si disponible
const getLayout = Component.getLayout ?? ((page) => page)
return getLayout(<Component {...pageProps} />)
}
export default function MyApp({ Component, pageProps }) {
// Utilise la mise en page définie au niveau de la page, si disponible
const getLayout = Component.getLayout ?? ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Récupération de données
Dans votre mise en page, vous pouvez récupérer des données côté client en utilisant useEffect
ou une bibliothèque comme SWR. Comme ce fichier n'est pas une Page, vous ne pouvez pas utiliser getStaticProps
ou getServerSideProps
actuellement.
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
const { data, error } = useSWR('/api/navigation', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return (
<>
<Navbar links={data.links} />
<main>{children}</main>
<Footer />
</>
)
}