Comment utiliser les composants Serveur et Client
Par défaut, les layouts et les pages sont des composants Serveur (Server Components), ce qui vous permet de récupérer des données et d'afficher des parties de votre interface côté serveur, de mettre en cache le résultat si nécessaire, et de le transmettre au client. Lorsque vous avez besoin d'interactivité ou d'API navigateur, vous pouvez utiliser des composants Client (Client Components) pour ajouter des fonctionnalités.
Cette page explique comment les composants Serveur et Client fonctionnent dans Next.js et quand les utiliser, avec des exemples de leur combinaison dans votre application.
Quand utiliser les composants Serveur et Client ?
Les environnements client et serveur ont des capacités différentes. Les composants Serveur et Client vous permettent d'exécuter une logique dans chaque environnement selon votre cas d'utilisation.
Utilisez des composants Client lorsque vous avez besoin :
- D'un état (State) et de gestionnaires d'événements (event handlers). Par exemple
onClick
,onChange
. - D'une logique de cycle de vie (Lifecycle logic). Par exemple
useEffect
. - D'API spécifiques au navigateur. Par exemple
localStorage
,window
,Navigator.geolocation
, etc. - De hooks personnalisés (Custom hooks).
Utilisez des composants Serveur lorsque vous avez besoin :
- De récupérer des données depuis des bases de données ou des API proches de la source.
- D'utiliser des clés API, des tokens et d'autres secrets sans les exposer au client.
- De réduire la quantité de JavaScript envoyée au navigateur.
- D'améliorer le First Contentful Paint (FCP), et de transmettre progressivement le contenu au client.
Par exemple, le composant <Page>
est un composant Serveur qui récupère des données sur un post, et les transmet comme props au composant <LikeButton>
qui gère l'interactivité côté client.
Comment fonctionnent les composants Serveur et Client dans Next.js ?
Côté serveur
Côté serveur, Next.js utilise les API de React pour orchestrer le rendu. Le travail de rendu est divisé en segments, par route individuelle (layouts et pages) :
- Les composants Serveur sont rendus dans un format spécial appelé React Server Component Payload (RSC Payload).
- Les composants Client et le RSC Payload sont utilisés pour prerendre (prerender) le HTML.
Qu'est-ce que le React Server Component Payload (RSC) ?
Le RSC Payload est une représentation binaire compacte de l'arbre des composants Serveur rendus. Il est utilisé par React côté client pour mettre à jour le DOM du navigateur. Le RSC Payload contient :
- Le résultat rendu des composants Serveur
- Des emplacements pour les composants Client qui doivent être rendus et des références à leurs fichiers JavaScript
- Toutes les props passées d'un composant Serveur à un composant Client
Côté client (premier chargement)
Ensuite, côté client :
- Le HTML est utilisé pour afficher immédiatement un aperçu rapide et non interactif de la route à l'utilisateur.
- Le RSC Payload est utilisé pour réconcilier les arbres des composants Client et Serveur.
- Le JavaScript est utilisé pour hydrater (hydrate) les composants Client et rendre l'application interactive.
Qu'est-ce que l'hydratation ?
L'hydratation est le processus de React pour attacher des gestionnaires d'événements (event handlers) au DOM, afin de rendre le HTML statique interactif.
Navigations suivantes
Lors des navigations suivantes :
- Le RSC Payload est préchargé et mis en cache pour une navigation instantanée.
- Les composants Client sont entièrement rendus côté client, sans le HTML rendu côté serveur.
Exemples
Utilisation de composants Client
Vous pouvez créer un composant Client en ajoutant la directive "use client"
en haut du fichier, avant vos imports.
"use client"
est utilisé pour déclarer une frontière entre les graphes (arbres) de modules Serveur et Client.
Une fois qu'un fichier est marqué avec "use client"
, tous ses imports et composants enfants sont considérés comme faisant partie du bundle client. Cela signifie que vous n'avez pas besoin d'ajouter la directive à chaque composant destiné au client.
Réduction de la taille du bundle JS
Pour réduire la taille de vos bundles JavaScript côté client, ajoutez 'use client'
à des composants interactifs spécifiques au lieu de marquer de grandes parties de votre interface comme composants Client.
Par exemple, le composant <Layout>
contient principalement des éléments statiques comme un logo et des liens de navigation, mais inclut une barre de recherche interactive. <Search />
est interactive et doit être un composant Client, cependant, le reste du layout peut rester un composant Serveur.
Passage de données des composants Serveur aux composants Client
Vous pouvez passer des données des composants Serveur aux composants Client en utilisant des props.
Alternativement, vous pouvez diffuser (stream) des données d'un composant Serveur vers un composant Client avec le Hook use
. Voir un exemple.
Bon à savoir : Les props passées aux composants Client doivent être sérialisables par React.
Entrelacement des composants Serveur et Client
Vous pouvez passer des composants Serveur comme prop à un composant Client. Cela vous permet d'imbriquer visuellement une interface rendue côté serveur dans des composants Client.
Un motif courant consiste à utiliser children
pour créer un slot dans un <ClientComponent>
. Par exemple, un composant <Cart>
qui récupère des données côté serveur, à l'intérieur d'un composant <Modal>
qui utilise un état client pour basculer la visibilité.
Ensuite, dans un composant Serveur parent (par exemple <Page>
), vous pouvez passer un <Cart>
comme enfant du <Modal>
:
Dans ce motif, tous les composants Serveur seront rendus côté serveur à l'avance, y compris ceux passés comme props. Le RSC Payload résultant contiendra des références indiquant où les composants Client doivent être rendus dans l'arbre des composants.
Fournisseurs de contexte (Context providers)
Le contexte React est couramment utilisé pour partager un état global comme le thème actuel. Cependant, le contexte React n'est pas pris en charge dans les composants Serveur.
Pour utiliser un contexte, créez un composant Client qui accepte children
:
Ensuite, importez-le dans un composant Serveur (par exemple layout
) :
Votre composant Serveur pourra maintenant rendre directement votre fournisseur, et tous les autres composants Client dans votre application pourront consommer ce contexte.
Bon à savoir : Vous devriez rendre les fournisseurs aussi profondément que possible dans l'arbre – notez comment
ThemeProvider
n'englobe que{children}
au lieu de tout le document<html>
. Cela facilite l'optimisation par Next.js des parties statiques de vos composants Serveur.
Composants tiers
Lorsque vous utilisez un composant tiers qui dépend de fonctionnalités réservées au client, vous pouvez l'encapsuler dans un composant Client pour vous assurer qu'il fonctionne comme prévu.
Par exemple, le composant <Carousel />
peut être importé depuis le package acme-carousel
. Ce composant utilise useState
, mais il n'a pas encore la directive "use client"
.
Si vous utilisez <Carousel />
dans un composant Client, il fonctionnera comme prévu :
Cependant, si vous essayez de l'utiliser directement dans un composant Serveur, vous verrez une erreur. C'est parce que Next.js ne sait pas que <Carousel />
utilise des fonctionnalités réservées au client.
Pour résoudre ce problème, vous pouvez encapsuler les composants tiers qui dépendent de fonctionnalités réservées au client dans vos propres composants Client :
Maintenant, vous pouvez utiliser <Carousel />
directement dans un composant Serveur :
Conseil pour les auteurs de bibliothèques
Si vous créez une bibliothèque de composants, ajoutez la directive
"use client"
aux points d'entrée qui dépendent de fonctionnalités réservées au client. Cela permet à vos utilisateurs d'importer des composants dans des composants Serveur sans avoir besoin de créer des wrappers.Il est à noter que certains bundlers peuvent supprimer les directives
"use client"
. Vous pouvez trouver un exemple de configuration d'esbuild pour inclure la directive"use client"
dans les dépôts React Wrap Balancer et Vercel Analytics.
Prévenir l'intoxication de l'environnement
Les modules JavaScript peuvent être partagés entre les modules des composants Serveur et Client. Cela signifie qu'il est possible d'importer accidentellement du code réservé au serveur dans le client. Par exemple, considérez la fonction suivante :
Cette fonction contient une API_KEY
qui ne devrait jamais être exposée au client.
Dans Next.js, seules les variables d'environnement préfixées par NEXT_PUBLIC_
sont incluses dans le bundle client. Si les variables ne sont pas préfixées, Next.js les remplace par une chaîne vide.
Par conséquent, même si getData()
peut être importée et exécutée côté client, elle ne fonctionnera pas comme prévu.
Pour éviter une utilisation accidentelle dans les composants Client, vous pouvez utiliser le package server-only
.
Ensuite, importez le package dans un fichier contenant du code réservé au serveur :
Désormais, si vous essayez d'importer ce module dans un composant Client, une erreur sera générée lors de la compilation.
Bon à savoir : Le package correspondant
client-only
peut être utilisé pour marquer les modules contenant une logique réservée au client, comme du code accédant à l'objetwindow
.