Chargement différé (Lazy Loading)

Le chargement différé 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 (Client Components) 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 différé dans Next.js :

  1. En utilisant les importations dynamiques avec next/dynamic
  2. En utilisant React.lazy() avec Suspense

Par défaut, les composants serveur (Server Components) sont automatiquement découpés en morceaux (code split), et vous pouvez utiliser le streaming pour envoyer progressivement des éléments d'interface du serveur vers le client. Le chargement différé s'applique aux composants clients.

next/dynamic

next/dynamic est une combinaison de React.lazy() et Suspense. Il fonctionne de la même manière dans les répertoires app et pages pour permettre une migration progressive.

Exemples

En utilisant next/dynamic, le composant header ne sera pas inclus dans le bundle JavaScript initial de la page. La page affichera d'abord le fallback de Suspense, suivi du composant Header lorsque la limite de Suspense est résolue.

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  loading: () => <p>Chargement...</p>,
})

export default function Home() {
  return <DynamicHeader />
}

Bon à savoir : Dans import('chemin/vers/composant'), le chemin doit être explicitement écrit. Il ne peut pas s'agir d'une chaîne de modèle ni d'une variable. De plus, l'import() doit être à l'intérieur de l'appel dynamic() pour que Next.js puisse faire correspondre les bundles webpack / les identifiants de module à l'appel dynamic() spécifique et les précharger avant le rendu. dynamic() ne peut pas être utilisé à l'intérieur du rendu React car il doit être marqué au niveau supérieur du module pour que le préchargement fonctionne, similairement à React.lazy.

Avec des exportations nommées

Pour importer dynamiquement une exportation nommée, vous pouvez la retourner depuis la Promise renvoyée par import() :

components/hello.js
export function Hello() {
  return <p>Bonjour !</p>
}

// pages/index.js
import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() =>
  import('../components/hello').then((mod) => mod.Hello)
)

Sans SSR

Pour charger dynamiquement un composant côté client, vous pouvez utiliser l'option ssr pour désactiver le rendu côté serveur. Ceci est utile si une dépendance externe ou un composant repose sur des APIs navigateur comme window.

import dynamic from 'next/dynamic'

const DynamicHeader = dynamic(() => import('../components/header'), {
  ssr: false,
})

Avec des bibliothèques externes

Cet exemple utilise la bibliothèque externe fuse.js pour la recherche floue. Le module n'est chargé dans le navigateur qu'après que l'utilisateur ait saisi une recherche.

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>
  )
}