Comment charger à la demande les composants clients et les bibliothèques
Le chargement à la demande dans Next.js aide à améliorer les performances de chargement initial d'une application en réduisant la quantité de JavaScript nécessaire pour rendre une route.
Il vous permet de différer le chargement des composants clients et des bibliothèques importées, et de ne les inclure dans le bundle client que lorsqu'ils sont nécessaires. Par exemple, vous pourriez vouloir différer le chargement d'une modale jusqu'à ce qu'un utilisateur clique pour l'ouvrir.
Il existe deux façons d'implémenter le chargement à la demande dans Next.js :
- En utilisant les importations dynamiques avec
next/dynamic
- En utilisant
React.lazy()
avec Suspense
Par défaut, les composants serveur sont automatiquement découpés en morceaux (code splitting), et vous pouvez utiliser le streaming pour envoyer progressivement des éléments d'interface du serveur vers le client. Le chargement à la demande s'applique aux composants clients.
next/dynamic
next/dynamic
est une combinaison de React.lazy()
et de Suspense. Il se comporte de la même manière dans les répertoires app
et pages
pour permettre une migration progressive.
Exemples
Importation de composants clients
'use client'
import { useState } from 'react'
import dynamic from 'next/dynamic'
// Composants clients :
const ComponentA = dynamic(() => import('../components/A'))
const ComponentB = dynamic(() => import('../components/B'))
const ComponentC = dynamic(() => import('../components/C'), { ssr: false })
export default function ClientComponentExample() {
const [showMore, setShowMore] = useState(false)
return (
<div>
{/* Chargement immédiat, mais dans un bundle client séparé */}
<ComponentA />
{/* Chargement à la demande, uniquement si la condition est remplie */}
{showMore && <ComponentB />}
<button onClick={() => setShowMore(!showMore)}>Basculer</button>
{/* Chargement uniquement côté client */}
<ComponentC />
</div>
)
}
Remarque : Lorsqu'un composant serveur importe dynamiquement un composant client, le découpage en morceaux (code splitting) automatique n'est pas actuellement pris en charge.
Désactivation du SSR
Lors de l'utilisation de React.lazy()
et Suspense, les composants clients seront prérendus (SSR) par défaut.
Remarque : L'option
ssr: false
ne fonctionnera que pour les composants clients. Déplacez-la dans les composants clients pour garantir le bon fonctionnement du découpage en morceaux côté client.
Si vous souhaitez désactiver le prérendu pour un composant client, vous pouvez utiliser l'option ssr
définie sur false
:
const ComponentC = dynamic(() => import('../components/C'), { ssr: false })
Importation de composants serveur
Si vous importez dynamiquement un composant serveur, seuls les composants clients enfants du composant serveur seront chargés à la demande - pas le composant serveur lui-même. Cela aidera également à précharger les ressources statiques telles que le CSS lorsque vous l'utilisez dans les composants serveur.
import dynamic from 'next/dynamic'
// Composant serveur :
const ServerComponent = dynamic(() => import('../components/ServerComponent'))
export default function ServerComponentExample() {
return (
<div>
<ServerComponent />
</div>
)
}
Remarque : L'option
ssr: false
n'est pas prise en charge dans les composants serveur. Vous verrez une erreur si vous essayez de l'utiliser dans les composants serveur.ssr: false
n'est pas autorisé avecnext/dynamic
dans les composants serveur. Veuillez le déplacer dans un composant client.
Chargement de bibliothèques externes
Les bibliothèques externes peuvent être chargées à la demande en utilisant la fonction import()
. Cet exemple utilise la bibliothèque externe fuse.js
pour la recherche floue. Le module n'est chargé côté client qu'après que l'utilisateur a saisi dans le champ de recherche.
'use client'
import { useState } from 'react'
const names = ['Tim', 'Joe', 'Bel', 'Lee']
export default function Page() {
const [results, setResults] = useState()
return (
<div>
<input
type="text"
placeholder="Rechercher"
onChange={async (e) => {
const { value } = e.currentTarget
// Chargement dynamique de fuse.js
const Fuse = (await import('fuse.js')).default
const fuse = new Fuse(names)
setResults(fuse.search(value))
}}
/>
<pre>Résultats : {JSON.stringify(results, null, 2)}</pre>
</div>
)
}
Ajout d'un composant de chargement personnalisé
'use client'
import dynamic from 'next/dynamic'
const WithCustomLoading = dynamic(
() => import('../components/WithCustomLoading'),
{
loading: () => <p>Chargement...</p>,
}
)
export default function Page() {
return (
<div>
{/* Le composant de chargement sera affiché pendant le chargement de <WithCustomLoading/> */}
<WithCustomLoading />
</div>
)
}
Importation d'exportations nommées
Pour importer dynamiquement une exportation nommée, vous pouvez la retourner depuis la Promise retournée par la fonction import()
:
'use client'
export function Hello() {
return <p>Bonjour !</p>
}
import dynamic from 'next/dynamic'
const ClientComponent = dynamic(() =>
import('../components/hello').then((mod) => mod.Hello)
)