Liaison et navigation

Il existe quatre façons de naviguer entre les routes dans Next.js :

Cette page expliquera comment utiliser chacune de ces options et approfondira le fonctionnement de la navigation.

<Link> est un composant intégré qui étend la balise HTML <a> pour fournir un préchargement et une navigation côté client entre les routes. C'est la méthode principale et recommandée pour naviguer entre les routes dans Next.js.

Vous pouvez l'utiliser en l'important depuis next/link et en passant une prop href au composant :

import Link from 'next/link'

export default function Page() {
  return <Link href="/dashboard">Tableau de bord</Link>
}
import Link from 'next/link'

export default function Page() {
  return <Link href="/dashboard">Tableau de bord</Link>
}

Il existe d'autres props optionnelles que vous pouvez passer à <Link>. Consultez la référence API pour en savoir plus.

Exemples

Liaison vers des segments dynamiques

Lors de la liaison vers des segments dynamiques, vous pouvez utiliser des littéraux de gabarit et interpolation pour générer une liste de liens. Par exemple, pour générer une liste d'articles de blog :

app/blog/PostList.js
import Link from 'next/link'

export default function PostList({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

Vérification des liens actifs

Vous pouvez utiliser usePathname() pour déterminer si un lien est actif. Par exemple, pour ajouter une classe au lien actif, vous pouvez vérifier si le pathname actuel correspond au href du lien :

'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Links() {
  const pathname = usePathname()

  return (
    <nav>
      <ul>
        <li>
          <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
            Accueil
          </Link>
        </li>
        <li>
          <Link
            className={`link ${pathname === '/about' ? 'active' : ''}`}
            href="/about"
          >
            À propos
          </Link>
        </li>
      </ul>
    </nav>
  )
}
'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function Links() {
  const pathname = usePathname()

  return (
    <nav>
      <ul>
        <li>
          <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
            Accueil
          </Link>
        </li>
        <li>
          <Link
            className={`link ${pathname === '/about' ? 'active' : ''}`}
            href="/about"
          >
            À propos
          </Link>
        </li>
      </ul>
    </nav>
  )
}

Défilement vers un id

Le comportement par défaut du routeur App de Next.js est de faire défiler vers le haut d'une nouvelle route ou de maintenir la position de défilement pour la navigation avant et arrière.

Si vous souhaitez faire défiler vers un id spécifique lors de la navigation, vous pouvez ajouter à votre URL un lien de hachage # ou simplement passer un lien de hachage à la prop href. Ceci est possible car <Link> se rend sous forme d'élément <a>.

<Link href="/dashboard#settings">Paramètres</Link>

// Sortie
<a href="/dashboard#settings">Paramètres</a>

Bon à savoir :

  • Next.js fera défiler vers la Page si elle n'est pas visible dans la fenêtre d'affichage lors de la navigation.

Désactivation de la restauration du défilement

Le comportement par défaut du routeur App de Next.js est de faire défiler vers le haut d'une nouvelle route ou de maintenir la position de défilement pour la navigation avant et arrière. Si vous souhaitez désactiver ce comportement, vous pouvez passer scroll={false} au composant <Link>, ou scroll: false à router.push() ou router.replace().

// next/link
<Link href="/dashboard" scroll={false}>
  Tableau de bord
</Link>
// useRouter
import { useRouter } from 'next/navigation'

const router = useRouter()

router.push('/dashboard', { scroll: false })

Hook useRouter()

Le hook useRouter vous permet de changer programmatiquement les routes depuis des Composants Client.

app/page.js
'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Tableau de bord
    </button>
  )
}

Pour une liste complète des méthodes de useRouter, consultez la référence API.

Recommandation : Utilisez le composant <Link> pour naviguer entre les routes, sauf si vous avez une exigence spécifique pour utiliser useRouter.

Fonction redirect

Pour les Composants Serveur, utilisez la fonction redirect à la place.

import { redirect } from 'next/navigation'

async function fetchTeam(id: string) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }: { params: { id: string } }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect('/login')
  }

  // ...
}
import { redirect } from 'next/navigation'

async function fetchTeam(id) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }) {
  const team = await fetchTeam(params.id)
  if (!team) {
    redirect('/login')
  }

  // ...
}

Bon à savoir :

  • redirect renvoie par défaut un code d'état 307 (Redirection Temporaire). Lorsqu'il est utilisé dans une Action Serveur, il renvoie un 303 (Voir Autre), couramment utilisé pour rediriger vers une page de succès suite à une requête POST.
  • redirect lance en interne une erreur, il doit donc être appelé en dehors des blocs try/catch.
  • redirect peut être appelé dans des Composants Client pendant le processus de rendu mais pas dans les gestionnaires d'événements. Vous pouvez utiliser le hook useRouter à la place.
  • redirect accepte également les URL absolues et peut être utilisé pour rediriger vers des liens externes.
  • Si vous souhaitez rediriger avant le processus de rendu, utilisez next.config.js ou Middleware.

Consultez la référence API de redirect pour plus d'informations.

Utilisation de l'API History native

Next.js vous permet d'utiliser les méthodes natives window.history.pushState et window.history.replaceState pour mettre à jour la pile d'historique du navigateur sans recharger la page.

Les appels pushState et replaceState s'intègrent au routeur Next.js, vous permettant de synchroniser avec usePathname et useSearchParams.

window.history.pushState

Utilisez-la pour ajouter une nouvelle entrée à la pile d'historique du navigateur. L'utilisateur peut naviguer vers l'état précédent. Par exemple, pour trier une liste de produits :

'use client'

import { useSearchParams } from 'next/navigation'

export default function SortProducts() {
  const searchParams = useSearchParams()

  function updateSorting(sortOrder: string) {
    const params = new URLSearchParams(searchParams.toString())
    params.set('sort', sortOrder)
    window.history.pushState(null, '', `?${params.toString()}`)
  }

  return (
    <>
      <button onClick={() => updateSorting('asc')}>Trier par ordre croissant</button>
      <button onClick={() => updateSorting('desc')}>Trier par ordre décroissant</button>
    </>
  )
}
'use client'

import { useSearchParams } from 'next/navigation'

export default function SortProducts() {
  const searchParams = useSearchParams()

  function updateSorting(sortOrder) {
    const params = new URLSearchParams(searchParams.toString())
    params.set('sort', sortOrder)
    window.history.pushState(null, '', `?${params.toString()}`)
  }

  return (
    <>
      <button onClick={() => updateSorting('asc')}>Trier par ordre croissant</button>
      <button onClick={() => updateSorting('desc')}>Trier par ordre décroissant</button>
    </>
  )
}

window.history.replaceState

Utilisez-la pour remplacer l'entrée actuelle dans la pile d'historique du navigateur. L'utilisateur ne peut pas naviguer vers l'état précédent. Par exemple, pour changer la langue de l'application :

'use client'

import { usePathname } from 'next/navigation'

export function LocaleSwitcher() {
  const pathname = usePathname()

  function switchLocale(locale: string) {
    // Par exemple '/en/about' ou '/fr/contact'
    const newPath = `/${locale}${pathname}`
    window.history.replaceState(null, '', newPath)
  }

  return (
    <>
      <button onClick={() => switchLocale('en')}>Anglais</button>
      <button onClick={() => switchLocale('fr')}>Français</button>
    </>
  )
}
'use client'

import { usePathname } from 'next/navigation'

export function LocaleSwitcher() {
  const pathname = usePathname()

  function switchLocale(locale) {
    // Par exemple '/en/about' ou '/fr/contact'
    const newPath = `/${locale}${pathname}`
    window.history.replaceState(null, '', newPath)
  }

  return (
    <>
      <button onClick={() => switchLocale('en')}>Anglais</button>
      <button onClick={() => switchLocale('fr')}>Français</button>
    </>
  )
}

Fonctionnement du routage et de la navigation

Le routeur App utilise une approche hybride pour le routage et la navigation. Sur le serveur, votre code d'application est automatiquement divisé en morceaux par segments de route. Et sur le client, Next.js précharge et met en cache les segments de route. Cela signifie que lorsqu'un utilisateur navigue vers une nouvelle route, le navigateur ne recharge pas la page, et seuls les segments de route qui changent sont re-rendus - améliorant ainsi l'expérience de navigation et les performances.

1. Découpage du code

Le découpage du code vous permet de diviser votre code d'application en petits paquets à télécharger et exécuter par le navigateur. Cela réduit la quantité de données transférées et le temps d'exécution pour chaque requête, améliorant ainsi les performances.

Les Composants Serveur permettent à votre code d'application d'être automatiquement découpé par segments de route. Cela signifie que seul le code nécessaire pour la route actuelle est chargé lors de la navigation.

2. Préchargement

Le préchargement est un moyen de précharger une route en arrière-plan avant que l'utilisateur ne la visite.

Il existe deux façons dont les routes sont préchargées dans Next.js :

  • Composant <Link> : Les routes sont automatiquement préchargées lorsqu'elles deviennent visibles dans la fenêtre d'affichage de l'utilisateur. Le préchargement se produit lorsque la page est chargée pour la première fois ou lorsqu'elle apparaît à l'écran par défilement.
  • router.prefetch() : Le hook useRouter peut être utilisé pour précharger les routes programmatiquement.

Le comportement de préchargement par défaut de <Link> (c'est-à-dire lorsque la prop prefetch n'est pas spécifiée ou définie sur null) est différent selon votre utilisation de loading.js. Seule la mise en page partagée, jusqu'au premier fichier loading.js dans l'arbre des composants rendus, est préchargée et mise en cache pendant 30s. Cela réduit le coût de récupération d'une route dynamique entière et signifie que vous pouvez afficher un état de chargement instantané pour un meilleur retour visuel aux utilisateurs.

Vous pouvez désactiver le préchargement en définissant la prop prefetch sur false. Alternativement, vous pouvez précharger les données complètes de la page au-delà des limites de chargement en définissant la prop prefetch sur true.

Consultez la référence API de <Link> pour plus d'informations.

Bon à savoir :

  • Le préchargement n'est pas activé en développement, uniquement en production.

3. Mise en cache

Next.js dispose d'un cache côté client en mémoire appelé Cache du Routeur. Lorsque les utilisateurs naviguent dans l'application, la charge utile du Composant Serveur React des segments de route préchargés et des routes visitées est stockée dans le cache.

Cela signifie que lors de la navigation, le cache est réutilisé autant que possible, au lieu de faire une nouvelle requête au serveur - améliorant les performances en réduisant le nombre de requêtes et les données transférées.

Apprenez-en plus sur le fonctionnement du Cache du Routeur et comment le configurer.

4. Rendu partiel

Le rendu partiel signifie que seuls les segments de route qui changent lors de la navigation sont re-rendus côté client, et que tous les segments partagés sont préservés.

Par exemple, lors de la navigation entre deux routes frères, /dashboard/settings et /dashboard/analytics, les pages settings et analytics seront rendues, et la mise en page partagée dashboard sera préservée.

Fonctionnement du rendu partiel

Sans rendu partiel, chaque navigation entraînerait le re-rendu complet de la page côté client. Le rendu uniquement du segment qui change réduit la quantité de données transférées et le temps d'exécution, améliorant ainsi les performances.

5. Navigation douce

Les navigateurs effectuent une "navigation dure" lors de la navigation entre les pages. Le routeur App de Next.js permet une "navigation douce" entre les pages, garantissant que seuls les segments de route qui ont changé sont re-rendus (rendu partiel). Cela permet de préserver l'état React côté client pendant la navigation.

6. Navigation avant et arrière

Par défaut, Next.js maintiendra la position de défilement pour les navigations avant et arrière, et réutilisera les segments de route dans le Cache du Routeur.

7. Routage entre pages/ et app/

Lors de la migration progressive de pages/ vers app/, le routeur Next.js gérera automatiquement la navigation dure entre les deux. Pour détecter les transitions de pages/ vers app/, il existe un filtre de routeur côté client qui utilise une vérification probabiliste des routes d'application, ce qui peut occasionnellement entraîner des faux positifs. Par défaut, ces occurrences devraient être très rares, car nous configurons la probabilité de faux positif à 0,01%. Cette probabilité peut être personnalisée via l'option experimental.clientRouterFilterAllowedRate dans next.config.js. Il est important de noter que réduire le taux de faux positifs augmentera la taille du filtre généré dans le paquet client.

Alternativement, si vous préférez désactiver complètement cette gestion et gérer manuellement le routage entre pages/ et app/, vous pouvez définir experimental.clientRouterFilter sur false dans next.config.js. Lorsque cette fonctionnalité est désactivée, les routes dynamiques dans pages qui chevauchent les routes d'app ne seront pas correctement naviguées par défaut.