Pages et Layouts

Le Pages Router dispose d'un système de routage basé sur le système de fichiers, construit autour du 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 via /about.

export default function About() {
  return <div>About</div>
}

Routes 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 via posts/1, posts/2, etc.

Pour en savoir plus sur le routage dynamique, consultez la documentation sur le routage dynamique.

Modèle de 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.

components/layout.js
import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

Exemples

Layout unique partagé avec une App personnalisée

Si vous n'avez qu'un seul layout pour toute votre application, vous pouvez créer une App personnalisée et encapsuler votre application avec le layout. 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).

pages/_app.js
import Layout from '../components/layout'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

Layouts par page

Si vous avez besoin de plusieurs layouts, vous pouvez ajouter une propriété getLayout à votre page, permettant de retourner un composant React pour le layout. Cela vous permet de définir le layout par page. Comme nous retournons une fonction, nous pouvons avoir des layouts imbriqués complexes si nécessaire.

pages/index.js

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>
  )
}
pages/_app.js
export default function MyApp({ Component, pageProps }) {
  // Utilise le layout défini 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 layout permet la persistance de l'état car l'arborescence des composants React est maintenue entre les transitions de page. Avec cette arborescence, 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

Récupération de données

Dans votre layout, 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.

components/layout.js
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>Échec du chargement</div>
  if (!data) return <div>Chargement...</div>

  return (
    <>
      <Navbar links={data.links} />
      <main>{children}</main>
      <Footer />
    </>
  )
}

On this page