Link
<Link>
est un composant React qui étend l'élément HTML <a>
pour fournir un préchargement (prefetching) et une navigation côté client entre les routes. C'est la méthode principale pour naviguer entre les routes dans Next.js.
Utilisation de base :
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>
}
Référence
Les propriétés suivantes peuvent être passées au composant <Link>
:
Propriété | Exemple | Type | Requis |
---|---|---|---|
href | href="/dashboard" | String ou Object | Oui |
replace | replace={false} | Boolean | - |
scroll | scroll={false} | Boolean | - |
prefetch | prefetch={false} | Boolean ou null | - |
onNavigate | onNavigate={(e) => {}} | Function | - |
Bon à savoir : Les attributs de balise
<a>
tels queclassName
outarget="_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' },
}}
>
À propos
</Link>
)
}
import Link from 'next/link'
// Naviguer vers /about?name=test
export default function Page() {
return (
<Link
href={{
pathname: '/about',
query: { name: 'test' },
}}
>
À propos
</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>
Tableau de bord
</Link>
)
}
import Link from 'next/link'
export default function Page() {
return (
<Link href="/dashboard" replace>
Tableau de bord
</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 n'essaiera 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 avecgetBoundingClientRect
. Next.js continue ensuite à travers les éléments frères jusqu'à identifier un élément défilable qui est visible dans la fenêtre d'affichage.
import Link from 'next/link'
export default function Page() {
return (
<Link href="/dashboard" scroll={false}>
Tableau de bord
</Link>
)
}
import Link from 'next/link'
export default function Page() {
return (
<Link href="/dashboard" scroll={false}>
Tableau de bord
</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 soit 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 limiteloading.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}>
Tableau de bord
</Link>
)
}
import Link from 'next/link'
export default function Page() {
return (
<Link href="/dashboard" prefetch={false}>
Tableau de bord
</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()
}}
>
Tableau de bord
</Link>
)
}
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()
}}
>
Tableau de bord
</Link>
)
}
Bon à savoir : Bien que
onClick
etonNavigate
puissent sembler similaires, ils servent des objectifs différents.onClick
s'exécute pour tous les événements de clic, tandis queonNavigate
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 pasonNavigate
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 aveconClick
mais pas aveconNavigate
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 création de liens vers des segments dynamiques, vous pouvez utiliser des littéraux de gabarit et l'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>
)
}
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 :
Défilement vers un id
Si vous souhaitez défiler vers un id
spécifique lors de la navigation, vous pouvez ajouter un lien de hachage #
à votre URL 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éfillera 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>
)
}
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
.
- Si vous utilisez la fonctionnalité JSX pragma d'emotion (
@jsx jsx
), vous devez utiliserpassHref
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.
Imbriquer 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>
)
}
import Link from 'next/link'
import React from 'react'
// `onClick`, `href`, et `ref` doivent être transmis à l'élément DOM
// pour un traitement correct
const MyButton = React.forwardRef(({ onClick, href }, ref) => {
return (
<a href={href} onClick={onClick} ref={ref}>
Cliquez ici
</a>
)
})
// Ajouter un nom d'affichage pour le composant (utile pour le débogage)
MyButton.displayName = 'MyButton'
export default function Page() {
return (
<Link href="/about" passHref legacyBehavior>
<MyButton />
</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éfillera vers le haut du premier élément de 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>
)
}
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 celle à 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 ce qui suit 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))
}
}
}
import { NextResponse } from 'next/server'
export function middleware(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>
)
}
'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 élégante pour partager cet état de blocage. Commencez par créer un contexte pour suivre l'état de blocage de la navigation :
Créez un composant de formulaire qui utilise 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>
)
}
'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>
)
}
'use client'
import Link from 'next/link'
import { useNavigationBlocker } from '../contexts/navigation-blocker'
export function CustomLink({ children, ...props }) {
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 :
Enfin, enveloppez votre application avec le NavigationBlockerProvider
dans la mise en page racine 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>
)
}
import { NavigationBlockerProvider } from './contexts/navigation-blocker'
export default function RootLayout({ children }) {
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 Tableau de bord</h1>
<Form />
</main>
</div>
)
}
import Nav from './components/nav'
import Form from './components/form'
export default function Page() {
return (
<div>
<Nav />
<main>
<h1>Bienvenue sur le Tableau de bord</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
Version | Modifications |
---|---|
v15.3.0 | Ajout de l'API onNavigate |
v13.0.0 | Ne nécessite plus une balise enfant <a> . Un codemod est fourni pour mettre à jour automatiquement votre codebase. |
v10.0.0 | Les props href pointant vers une route dynamique sont automatiquement résolues et ne nécessitent plus de prop as . |
v8.0.0 | Amélioration des performances de préchargement. |
v1.0.0 | Introduction de next/link . |