Link

<Link> est un composant React qui étend l'élément HTML <a> pour fournir un préchargement et une navigation côté client entre les routes. C'est le moyen principal de naviguer entre les routes dans Next.js.

Utilisation de base :

import Link from 'next/link'

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

Référence

Les propriétés suivantes peuvent être passées au composant <Link> :

PropriétéExempleTypeRequis
hrefhref="/dashboard"String ou ObjectOui
replacereplace={false}Boolean-
scrollscroll={false}Boolean-
prefetchprefetch={false}Boolean ou null-
onNavigateonNavigate={(e) => {}}Function-

Bon à savoir : Les attributs de balise <a> comme className ou target="_blank" peuvent être ajoutés à <Link> comme propriétés et seront transmis à l'élément <a> sous-jacent.

href (requis)

Le chemin ou l'URL vers lequel naviguer.

import Link from 'next/link'

// Naviguer vers /about?name=test
export default function Page() {
  return (
    <Link
      href={{
        pathname: '/about',
        query: { name: 'test' },
      }}
    >
      About
    </Link>
  )
}

replace

Par défaut false. Lorsque true, next/link remplacera l'état actuel de l'historique au lieu d'ajouter une nouvelle URL dans la pile d'historique du navigateur.

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/dashboard" replace>
      Dashboard
    </Link>
  )
}

scroll

Par défaut true. Le comportement de défilement par défaut de <Link> dans Next.js est de maintenir la position de défilement, similaire à la façon dont les navigateurs gèrent la navigation avant et arrière. Lorsque vous naviguez vers une nouvelle Page, la position de défilement restera la même tant que la Page est visible dans la fenêtre d'affichage. Cependant, si la Page n'est pas visible dans la fenêtre d'affichage, Next.js fera défiler jusqu'au premier élément de la Page.

Lorsque scroll = {false}, Next.js ne tentera pas de faire défiler jusqu'au premier élément de la Page.

Bon à savoir : Next.js vérifie si scroll: false avant de gérer le comportement de défilement. Si le défilement est activé, il identifie le nœud DOM pertinent pour la navigation et inspecte chaque élément de premier niveau. Tous les éléments non défilables et ceux sans HTML rendu sont contournés, cela inclut les éléments positionnés en sticky ou fixed, et les éléments non visibles tels que ceux calculés avec getBoundingClientRect. Next.js continue ensuite à travers les éléments frères jusqu'à identifier un élément défilable visible dans la fenêtre d'affichage.

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/dashboard" scroll={false}>
      Dashboard
    </Link>
  )
}

prefetch

Le préchargement se produit lorsqu'un composant <Link /> entre dans la fenêtre d'affichage de l'utilisateur (initialement ou par défilement). Next.js précharge et charge la route liée (désignée par href) et ses données en arrière-plan pour améliorer les performances des navigations côté client. Si les données préchargées ont expiré au moment où l'utilisateur survole un <Link />, Next.js tentera de les précharger à nouveau. Le préchargement n'est activé qu'en production.

Les valeurs suivantes peuvent être passées à la propriété prefetch :

  • null (par défaut) : Le comportement de préchargement dépend du fait que la route est statique ou dynamique. Pour les routes statiques, la route complète sera préchargée (y compris toutes ses données). Pour les routes dynamiques, la route partielle jusqu'au segment le plus proche avec une limite loading.js sera préchargée.
  • true : La route complète sera préchargée pour les routes statiques et dynamiques.
  • false : Le préchargement ne se produira jamais, ni lors de l'entrée dans la fenêtre d'affichage ni lors du survol.
import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/dashboard" prefetch={false}>
      Dashboard
    </Link>
  )
}

onNavigate

Un gestionnaire d'événements appelé lors de la navigation côté client. Le gestionnaire reçoit un objet événement qui inclut une méthode preventDefault(), vous permettant d'annuler la navigation si nécessaire.

import Link from 'next/link'

export default function Page() {
  return (
    <Link
      href="/dashboard"
      onNavigate={(e) => {
        // Ne s'exécute que pendant la navigation SPA
        console.log('Navigation en cours...')

        // Optionnellement empêcher la navigation
        // e.preventDefault()
      }}
    >
      Dashboard
    </Link>
  )
}

Bon à savoir : Bien que onClick et onNavigate puissent sembler similaires, ils servent des objectifs différents. onClick s'exécute pour tous les événements de clic, tandis que onNavigate ne s'exécute que pendant la navigation côté client. Quelques différences clés :

  • Lors de l'utilisation de touches de modification (Ctrl/Cmd + Clic), onClick s'exécute mais pas onNavigate car Next.js empêche la navigation par défaut pour les nouveaux onglets.
  • Les URL externes ne déclencheront pas onNavigate car elle est uniquement pour les navigations côté client et de même origine.
  • Les liens avec l'attribut download fonctionneront avec onClick mais pas avec onNavigate car le navigateur traitera l'URL liée comme un téléchargement.

Exemples

Les exemples suivants démontrent comment utiliser le composant <Link> dans différents scénarios.

Lien 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 :

import Link from 'next/link'

interface Post {
  id: number
  title: string
  slug: string
}

export default function PostList({ posts }: { posts: Post[] }) {
  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>
      <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
        Accueil
      </Link>

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

Défilement vers un id

Si vous souhaitez 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 comme un élément <a>.

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

// Résultat
<a href="/dashboard#settings">Paramètres</a>

Bon à savoir :

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

Lien vers des segments de route dynamiques

Pour les segments de route dynamiques, il peut être pratique d'utiliser des littéraux de modèle pour créer le chemin du lien.

Par exemple, vous pouvez générer une liste de liens vers la route dynamique app/blog/[slug]/page.js :

import Link from 'next/link'

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

Si l'enfant est un composant personnalisé qui englobe une balise <a>

Si l'enfant de Link est un composant personnalisé qui englobe une balise <a>, vous devez ajouter passHref à Link. Ceci est nécessaire si vous utilisez des bibliothèques comme styled-components. Sans cela, la balise <a> n'aura pas l'attribut href, ce qui nuit à l'accessibilité de votre site et peut affecter le SEO. Si vous utilisez ESLint, il existe une règle intégrée next/link-passhref pour garantir une utilisation correcte de passHref.

import Link from 'next/link'
import styled from 'styled-components'

// Ceci crée un composant personnalisé qui englobe une balise <a>
const RedLink = styled.a`
  color: red;
`

function NavLink({ href, name }) {
  return (
    <Link href={href} passHref legacyBehavior>
      <RedLink>{name}</RedLink>
    </Link>
  )
}

export default NavLink
  • Si vous utilisez la fonctionnalité JSX pragma d'emotion (@jsx jsx), vous devez utiliser passHref même si vous utilisez directement une balise <a>.
  • Le composant doit prendre en charge la propriété onClick pour déclencher correctement la navigation.

Imbrication d'un composant fonctionnel

Si l'enfant de Link est un composant fonctionnel, en plus d'utiliser passHref et legacyBehavior, vous devez encapsuler le composant dans React.forwardRef :

import Link from 'next/link'
import React from 'react'

// Définir le type des props pour MyButton
interface MyButtonProps {
  onClick?: React.MouseEventHandler<HTMLAnchorElement>
  href?: string
}

// Utiliser React.ForwardRefRenderFunction pour typer correctement la ref transmise
const MyButton: React.ForwardRefRenderFunction<
  HTMLAnchorElement,
  MyButtonProps
> = ({ onClick, href }, ref) => {
  return (
    <a href={href} onClick={onClick} ref={ref}>
      Cliquez ici
    </a>
  )
}

// Utiliser React.forwardRef pour encapsuler le composant
const ForwardedMyButton = React.forwardRef(MyButton)

export default function Page() {
  return (
    <Link href="/about" passHref legacyBehavior>
      <ForwardedMyButton />
    </Link>
  )
}

Remplacer l'URL au lieu de pousser

Le comportement par défaut du composant Link est de pousser une nouvelle URL dans la pile history. Vous pouvez utiliser la prop replace pour éviter d'ajouter une nouvelle entrée, comme dans l'exemple suivant :

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/about" replace>
      À propos
    </Link>
  )
}
import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/about" replace>
      À propos
    </Link>
  )
}

Désactiver le défilement vers le haut de la page

Le comportement de défilement par défaut de <Link> dans Next.js est de maintenir la position de défilement, similaire à la façon dont les navigateurs gèrent la navigation avant et arrière. Lorsque vous naviguez vers une nouvelle Page, la position de défilement restera la même tant que la Page est visible dans la fenêtre d'affichage.

Cependant, si la Page n'est pas visible dans la fenêtre d'affichage, Next.js défiera vers le haut du premier élément de la Page. Si vous souhaitez désactiver ce comportement, vous pouvez passer scroll={false} au composant <Link>, ou scroll: false à router.push() ou router.replace().

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/#hashid" scroll={false}>
      Désactive le défilement vers le haut
    </Link>
  )
}

Utilisation de router.push() ou router.replace() :

// useRouter
import { useRouter } from 'next/navigation'

const router = useRouter()

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

Préchargement des liens dans le Middleware

Il est courant d'utiliser le Middleware pour l'authentification ou d'autres fonctionnalités impliquant la réécriture de l'utilisateur vers une page différente. Pour que le composant <Link /> précharge correctement les liens avec des réécritures via le Middleware, vous devez indiquer à Next.js à la fois l'URL à afficher et l'URL à précharger. Cela est nécessaire pour éviter des requêtes inutiles vers le middleware afin de connaître la route correcte à précharger.

Par exemple, si vous souhaitez servir une route /dashboard avec des vues authentifiées et visiteurs, vous pouvez ajouter ceci dans votre Middleware pour rediriger l'utilisateur vers la bonne page :

import { NextResponse } from 'next/server'

export function middleware(request: Request) {
  const nextUrl = request.nextUrl
  if (nextUrl.pathname === '/dashboard') {
    if (request.cookies.authToken) {
      return NextResponse.rewrite(new URL('/auth/dashboard', request.url))
    } else {
      return NextResponse.rewrite(new URL('/public/dashboard', request.url))
    }
  }
}

Dans ce cas, vous devriez utiliser le code suivant dans votre composant <Link /> :

'use client'

import Link from 'next/link'
import useIsAuthed from './hooks/useIsAuthed' // Votre hook d'authentification

export default function Page() {
  const isAuthed = useIsAuthed()
  const path = isAuthed ? '/auth/dashboard' : '/public/dashboard'
  return (
    <Link as="/dashboard" href={path}>
      Dashboard
    </Link>
  )
}

Blocage de la navigation

Vous pouvez utiliser la prop onNavigate pour bloquer la navigation lorsque certaines conditions sont remplies, comme lorsqu'un formulaire contient des modifications non enregistrées. Lorsque vous devez bloquer la navigation dans plusieurs composants de votre application (par exemple empêcher la navigation depuis n'importe quel lien pendant qu'un formulaire est en cours de modification), React Context offre une solution propre pour partager cet état de blocage. Commencez par créer un contexte pour suivre l'état de blocage de la navigation :

'use client'

import { createContext, useState, useContext } from 'react'

interface NavigationBlockerContextType {
  isBlocked: boolean
  setIsBlocked: (isBlocked: boolean) => void
}

export const NavigationBlockerContext =
  createContext<NavigationBlockerContextType>({
    isBlocked: false,
    setIsBlocked: () => {},
  })

export function NavigationBlockerProvider({
  children,
}: {
  children: React.ReactNode
}) {
  const [isBlocked, setIsBlocked] = useState(false)

  return (
    <NavigationBlockerContext.Provider value={{ isBlocked, setIsBlocked }}>
      {children}
    </NavigationBlockerContext.Provider>
  )
}

export function useNavigationBlocker() {
  return useContext(NavigationBlockerContext)
}

Créez un composant de formulaire utilisant le contexte :

'use client'

import { useNavigationBlocker } from '../contexts/navigation-blocker'

export default function Form() {
  const { setIsBlocked } = useNavigationBlocker()

  return (
    <form
      onSubmit={(e) => {
        e.preventDefault()
        setIsBlocked(false)
      }}
      onChange={() => setIsBlocked(true)}
    >
      <input type="text" name="name" />
      <button type="submit">Enregistrer</button>
    </form>
  )
}

Créez un composant Link personnalisé qui bloque la navigation :

'use client'

import Link from 'next/link'
import { useNavigationBlocker } from '../contexts/navigation-blocker'

interface CustomLinkProps extends React.ComponentProps<typeof Link> {
  children: React.ReactNode
}

export function CustomLink({ children, ...props }: CustomLinkProps) {
  const { isBlocked } = useNavigationBlocker()

  return (
    <Link
      onNavigate={(e) => {
        if (
          isBlocked &&
          !window.confirm('Vous avez des modifications non enregistrées. Quitter quand même ?')
        ) {
          e.preventDefault()
        }
      }}
      {...props}
    >
      {children}
    </Link>
  )
}

Créez un composant de navigation :

'use client'

import { CustomLink as Link } from './custom-link'

export default function Nav() {
  return (
    <nav>
      <Link href="/">Accueil</Link>
      <Link href="/about">À propos</Link>
    </nav>
  )
}

Enfin, enveloppez votre application avec le NavigationBlockerProvider dans la racine de votre layout et utilisez les composants dans votre page :

import { NavigationBlockerProvider } from './contexts/navigation-blocker'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <NavigationBlockerProvider>{children}</NavigationBlockerProvider>
      </body>
    </html>
  )
}

Puis, utilisez les composants Nav et Form dans votre page :

import Nav from './components/nav'
import Form from './components/form'

export default function Page() {
  return (
    <div>
      <Nav />
      <main>
        <h1>Bienvenue sur le Dashboard</h1>
        <Form />
      </main>
    </div>
  )
}

Lorsqu'un utilisateur tente de naviguer en utilisant CustomLink alors que le formulaire contient des modifications non enregistrées, il sera invité à confirmer avant de quitter.

Historique des versions

VersionChangements
v15.3.0Ajout de l'API onNavigate
v13.0.0Ne nécessite plus une balise enfant <a>. Un codemod est fourni pour mettre à jour automatiquement votre codebase.
v10.0.0Les props href pointant vers une route dynamique sont automatiquement résolues et ne nécessitent plus de prop as.
v8.0.0Amélioration des performances de préchargement.
v1.0.0Introduction de next/link.