React a complètement transformé la façon dont nous créons des interfaces utilisateur en introduisant une conception basée sur les composants qui encourage l'efficacité et la réutilisation. Sa méthode déclarative et sa structure à base de composants ont gagné en popularité auprès des développeurs. Mais à mesure que vos projets gagnent en complexité, vous risquez de rencontrer des problèmes de performance en raison des méthodes de rendu et de récupération des données.
Dans les méthodes traditionnelles de rendu côté client, vous dépendez du navigateur pour exécuter JavaScript afin d'afficher l'interface utilisateur initiale. Cela peut entraîner des retards de chargement sur les appareils disposant de ressources limitées. L'extraction de données à partir d'une interface de programmation d'applications (API) introduit une charge supplémentaire sur ces appareils, ce qui peut entraîner un retard dans l'affichage du contenu et des interactions moins qu'idéales avec l'utilisateur.
Les composants serveur offrent une solution à ces obstacles en permettant le rendu des composants sur le serveur. Cela permet au serveur de diffuser les composants vers le côté client, ce qui améliore les performances et les processus de récupération des données puisque tout le traitement a lieu sur le serveur et non sur les appareils des utilisateurs.
Dans cet article, vous apprendrez comment les méthodes de rendu de React ont évolué au fil du temps, ainsi que les inconvénients de l'utilisation de React Suspense et du rendu côté serveur (SSR). En outre, vous découvrirez les composants serveur React (RSC) et la manière dont ils traitent ces problèmes.
Avant d'aborder les RSC, il est utile de comprendre les stratégies de rendu précédentes, telles que React Suspense et SSR.
React Suspense a été introduit pour gérer le rendu asynchrone dans les applications React. Il permet aux composants de "suspendre" le rendu jusqu'à ce que certaines conditions soient remplies, comme la récupération de données ou le fractionnement du code. Voici quelques-uns des avantages de Suspense :
React.lazy
pour permettre le fractionnement du code et améliorer les performances en chargeant les composants uniquement lorsqu'ils sont nécessaires.Cependant, React Suspense présente certaines limites dont il faut tenir compte lorsque vous faites évoluer votre application :
Suspense
et ErrorBoundary
, ce qui ajoute du code répétitif et rend plus difficile la cohérence et la maintenance de l'ensemble au fur et à mesure de la croissance de votre application.Lorsqu'il s'agit de SSR, les composants React sont rendus sur le serveur, puis le HTML entièrement généré est envoyé au client pour affichage. En revanche, avec les RSC, les composants individuels sont rendus lorsqu'ils sont prêts au lieu d'attendre le chargement de l'ensemble de l'application, comme c'est le cas avec les SSR. Cette approche présente de nombreux avantages :
La RSS présente également des limites qu'il convient de prendre en compte :
Les RSC sont un nouveau type de composant dans React qui fonctionne côté serveur, contrairement aux composants traditionnels, qui fonctionnent côté client. Ils aident à résoudre les problèmes associés à Suspense et aux SSR conventionnels en permettant aux composants d'être traités et diffusés en flux HTML du serveur vers le client. Les RSC gèrent également la récupération des données sur le serveur, en veillant à ce que les informations confidentielles, telles que les clés API, ne soient pas révélées au client.
Les RSC offrent des avantages significatifs :
Par rapport aux composants côté client, les RSC gèrent l'exécution, la gestion des données et les performances de manière différente.
Les composants traditionnels s'exécutent dans le navigateur (côté client), où JavaScript est nécessaire pour afficher l'interface utilisateur. Les RSC s'exécutent sur le serveur en envoyant du HTML pré-rendu à l'appareil client au lieu de tout traiter localement. Cette approche réduit la charge de travail de l'appareil de l'utilisateur et améliore la vitesse de chargement. Le traitement des mises en page et du contenu statique côté serveur est également idéal pour les composants non interactifs ou axés sur les données. Les composants clients peuvent être imbriqués dans les RSC lorsque l'interactivité est nécessaire, par exemple pour les boutons ou les formulaires, tout en préservant la sécurité des données sensibles sur le serveur.
Les composants traditionnels peuvent augmenter la taille du paquet JavaScript côté client, ce qui peut ralentir les performances de l'application. Les RSC n'augmentent pas la taille du paquet du client puisqu'ils fonctionnent côté serveur, ce qui permet de réduire les téléchargements et d'accélérer le temps de chargement des pages. Vous pouvez également utiliser les RSC pour améliorer la mise en cache. Le contenu rendu par le serveur est plus facile à mettre en cache, ce qui accélère les réponses pour les données fréquemment consultées, comme les produits les plus populaires d'une boutique en ligne, sans qu'il soit nécessaire d'interroger la base de données à plusieurs reprises.
Pour mettre en œuvre les RSC dans votre projet, suivez les étapes suivantes pour configurer votre environnement et commencer à utiliser efficacement les composants côté serveur et côté client.
Tout d'abord, assurez-vous que la dernière version de Node.js est installée sur votre machine. La première étape consiste à créer un nouveau projet React à partir de votre shell ou de votre terminal :
npx create-react-app votre-app --template cra-template-pwa cd votre-app
Une fois votre projet initialisé, installez les dépendances nécessaires aux RSCs :
npm install react@18 react-dom@18 babel-loader@8 @babel/preset-react webpack@5 webpack-cli
Pour plus d'informations, vous pouvez consulter la documentation officielle relative à chacune de ces bibliothèques : React, react-dom, webpack, Babel et webpack-cli.
Exécutez la commande suivante pour installer les chargeurs pour les feuilles de style CSS et les fichiers d'actifs comme les SVG, qui permettront à votre application de traiter et d'inclure les feuilles de style et les fichiers multimédias :
npm install css-loader style-loader file-loader --save-dev
Configurez Babel en créant un fichier .babelrc
à la racine de votre projet avec le contenu suivant :
{"presets" : ["@babel/preset-react"] }
Créez un nouveau fichier nommé webpack.config.js
dans le répertoire racine de votre projet et ajoutez la configuration suivante pour configurer webpack :
const path = require("path") ; module.exports = [ // Configuration côté serveur { entry : "./src/server.js", // Point d'entrée du serveur target : "node", output : { path : path.resolve(__dirname, "dist"), filename : "server.js", }, module : { rules : [ { test : /\c.jsx?$/, use : "babel-loader", exclude : /node_modules/, }, { test : /\.css$/, // Règle pour les fichiers CSS use : ["style-loader", "css-loader"], }, { test : /\.(png|jpe?g|gif|svg)$/, // Règle pour les fichiers images à utiliser : ["file-loader"], }, ], }, resolve : { extensions : [".js", ".jsx"], }, }, // Configuration côté client { entry : "./src/index.js", // Point d'entrée du client target : "web", // Ceci indique à Webpack d'empaqueter pour le navigateur output : { path : path.resolve(__dirname, "dist"), filename : "client.js", // Bundle côté client }, module : { rules : [ { test : /\c.jsx?$/, use : "babel-loader", exclude : /node_modules/, }, { test : /\.css$/, // Règle pour les fichiers CSS use : ["style-loader", "css-loader"], }, { test : /\.(png|jpe?g|gif|svg)$/, // Règle pour les fichiers images à utiliser : ["file-loader"], }, ], }, resolve : { extensions : [".js", ".jsx"], }, }, ] ;
Avec webpack configuré, vous pouvez maintenant créer un fichier nommé server.js
dans le dossier src
avec le code suivant pour mettre en place le point d'entrée de votre serveur :
import React from "react" ; const express = require("express") ; const ReactDOMServer = require("react-dom/server") ; const App = require("./App").default ; const app = express() ; // Servez les fichiers statiques du dossier 'dist' (où Webpack placera client.js) app.use(express.static("dist")) ; app.get("*", (req, res) => { const appHtml = ReactDOMServer.renderToString(<App />) ; res.send(` < !DOCTYPE html> <html lang="en"> <head><title>Composants du serveur React</title></head><body> <div id="root">${appHtml}</div> < !-- Inclure le bundle côté client --> <script src="/client.js"></script> </body> </html> `) ; }) ; app.listen(3000, () => console.log("Server running on port 3000")) ;
Dans le dossier src
, créez un nouveau fichier appelé UserList.server.js
pour mettre en place un composant serveur de base qui récupère les données :
import React from "react" ; function UserList() { // Tableau fictif d'utilisateurs const users = [ { id : 1, name : "John Doe" }, { id : 2, name : "Jane Smith" }, { id : 3, name : "Alice Johnson" }, ] ; return ( <ul> {users.map((user) => ( <li key={user.id}>{user.name}</li> ))} </ul> ) ; } export default UserList ;
Ce composant affiche les données relatives aux utilisateurs et renvoie une liste HTML. Pour ajouter une interactivité côté client, créez un fichier appelé Counter.client.js
dans le répertoire src
pour votre composant client :
import React, { useState } from "react" ; function Counter({ initialCount }) { const [count, setCount] = useState(initialCount) ; return ( <div><button onClick={() => {setCount((prevCount) => {const newCount = prevCount + 1 ;return newCount ; }) ;}} >Incrémenter de 1 </button> <p>Compte : {count}</p> </div> ) ; } export default Counter ;
De cette manière, le serveur initialise l'état et le client gère l'interactivité. Vous avez maintenant mis en place un flux de travail complet pour les RSC, créé un composant serveur, transmis des données à un composant client et activé l'interactivité côté client.
Ensuite, mettez à jour src/App.js
pour inclure le code suivant, qui intègre les composants serveur et client :
import React from "react" ; import UserList from "./UserList.server" ; import Counter from "./Counter.client" ; function App() { return ( <div> <h1>Utilisateurs</h1> <UserList /> <Counter initialCount={50} /> </div> ) ; } export default App ;
À présent, lorsque le serveur effectue le rendu du composant App, il effectue également le rendu du tableau de bord
UserList
en tant que composant serveur et envoie le code HTML au client.
Pour exécuter votre serveur, regroupez le code et démarrez-le :
npx webpack node dist/server.js
En exécutant ces commandes, vous obtiendrez un serveur fonctionnant sur le port 3000
. À ce stade, votre application effectue le rendu des composants React sur le client et le serveur !
Étant donné que les RSC gèrent la majeure partie du rendu sur le serveur, le fait de transférer autant que possible le rendu de votre application sur le serveur peut améliorer considérablement les performances tout en conservant les fonctionnalités interactives intactes lorsque cela est nécessaire. Voici quelques bonnes pratiques qui peuvent vous aider à atteindre cet objectif et à améliorer la vitesse, la flexibilité et la facilité de gestion de votre application avec les RSC.
Tout d'abord, utilisez les RSC pour récupérer des données dans les API ou les bases de données. Si vous avez déjà récupéré des données sur le serveur, ne les récupérez pas à nouveau sur le client. Par exemple, si vous chargez les données de l'utilisateur sur le serveur et les transmettez au client, il n'est pas nécessaire de faire un deuxième appel à l'API du côté du client, à moins que les données ne changent.
La décomposition du code en petits morceaux et le chargement sélectif des scripts nécessaires à l'aide d'outils tels que Vite ou webpack peuvent contribuer à améliorer les temps de chargement. Créez des composants qui peuvent être réutilisés dans l'ensemble de votre application. Par exemple, si plusieurs pages doivent afficher une liste d'utilisateurs, créez un composant UserList
qui fonctionnera partout.
Enfin, les composants serveur doivent rester légers en se concentrant uniquement sur le rendu des données, car ils n'ont pas besoin de gérer l'état comme le font les composants clients. Concentrez-vous sur la légèreté et la responsabilité du rendu des données. N'hydratez que les parties d'une page qui doivent être interactives. Par exemple, si la page est essentiellement statique mais qu'elle comporte un formulaire ou un bouton interactif, n'hydratez que ces composants.
Bien que les RSC présentent des avantages, il est également important de comprendre les obstacles et les limites liés à leur intégration dans votre projet.
Les composants serveur ne peuvent pas interagir avec les méthodes de cycle de vie telles que useEffect
ou useState
. Cela signifie que vous ne pouvez pas gérer l'interactivité côté client dans les composants serveur. Par exemple, si un formulaire est rendu côté serveur, vous aurez besoin d'un composant client pour gérer les modifications d'entrée en temps réel.
Lorsque vous utilisez des composants côté client et côté serveur dans vos projets, il est important de gérer l'interaction entre ces deux types de composants dans l'ensemble de votre application afin d'éviter tout problème. Par exemple, si votre application récupère des données sur le serveur et laisse les utilisateurs modifier ces données localement sur leurs appareils, vous risquez d'être confronté à des problèmes de cohérence des données entre le serveur et les composants côté client.
Les composants du serveur ne peuvent utiliser que des éléments sérialisables, ce qui signifie que vous ne pouvez pas transmettre de fonctions, de symboles ou d'objets complexes qui ne peuvent pas être sérialisés. Par exemple, l'envoi d'une fonction de rappel d'un composant serveur à un composant client entraînera l'affichage d'un message d'erreur. Les composants côté serveur n'ont pas accès aux API du navigateur telles que window
, document
ou localStorage
. Si vous devez interagir avec le DOM, vous devez le faire dans un composant client.
Si le code HTML affiché par le serveur ne correspond pas à ce que le JavaScript côté client attend, cela peut entraîner des problèmes au cours du processus d'hydratation. Par exemple, les différences de formatage des dates entre le serveur et le client peuvent entraîner de subtiles discordances. Les problèmes d'hydratation peuvent être difficiles à déboguer car la cause première n'est pas toujours évidente.
Certaines bibliothèques tierces peuvent ne pas fonctionner correctement avec les RSC, en particulier celles qui dépendent fortement des techniques de rendu côté client ou des API spécifiques aux navigateurs. Par exemple, des bibliothèques telles que react-router-dom
nécessitent un rendu côté client. Il se peut que vous deviez remplacer ou adapter certaines bibliothèques pour qu'elles fonctionnent avec les RSC.
Il existe des solutions pratiques que vous pouvez mettre en œuvre pour maintenir la cohérence et résoudre les problèmes courants liés aux RSC.
Utilisez des outils de gestion d'état qui fonctionnent à la fois sur le serveur et le client, comme Redux ou Zustand. Ces bibliothèques vous permettent de centraliser votre état afin que les composants rendus par le serveur et les composants côté client puissent accéder aux mêmes données. Par exemple, vous pouvez utiliser Redux pour stocker un état global disponible pour les deux parties de l'application.
Veillez à maintenir un flux de données entre le serveur et le client en partageant le contexte. Par exemple, lorsque vous déplacez des données utilisateur entre les composants serveur et client, assurez-vous que l'information est gérée de manière centralisée afin d'éviter toute divergence.
Envisagez d'utiliser des outils de développement ou des linters de code pour identifier les propriétés non sérialisables susceptibles de poser des problèmes avec les RSC. Par exemple, des outils tels que ESLint peuvent être configurés pour détecter les accessoires de fonction transmis par des composants basés sur des serveurs.
Veillez à remanier les composants pour vous assurer que les props peuvent être sérialisés et éviter tout problème avec les SSR. Une façon de le faire est de déplacer certaines opérations, comme les gestionnaires d'événements, vers les composants clients. Par exemple, lorsque vous passez une fonction de rappel à partir d'un composant serveur, assurez-vous que le code est ajusté pour que l'opération se produise dans le composant client où elle est utilisée.
La résolution des problèmes d'hydratation nécessite des techniques de test et de débogage proactives :
Si un logiciel tiers ne fonctionne pas avec les composants du serveur comme l'exigent les exigences de votre projet, étudiez d'autres options compatibles avec le serveur. Si vous utilisez une bibliothèque open source pour votre projet, vous pouvez envisager de contribuer à son développement en y incluant la prise en charge de RSC. En contribuant, vous pouvez améliorer votre propre application et avoir un impact positif sur la communauté élargie qui s'appuie sur la même bibliothèque pour son travail.
En relevant ces défis avec des stratégies appropriées en place, vous pouvez naviguer efficacement dans les limites des RSC et construire des applications robustes et performantes.
Dans cet article, nous avons expliqué les techniques de rendu de React. Nous avons présenté React Suspense et SSR et fourni un guide plus approfondi des RSC. Vous pouvez utiliser les RSC pour améliorer les performances de votre application en réduisant le besoin de traitement JavaScript côté client et en accélérant le chargement initial des pages.
Si vous souhaitez essayer les RSC dans vos projets, la première étape consiste à identifier les composants de votre application qui pourraient bénéficier des avantages des SSR. Vous pouvez ensuite intégrer progressivement les RSC dans votre base de code.
La mise en œuvre de l'infrastructure pour le SSR et les composants du serveur peut s'avérer complexe. L'utilisation d'Upsun, une plateforme en tant que service (PaaS), simplifie le déploiement et la mise à l'échelle de vos applications React. Grâce à sa prise en charge intégrée de Node.js et à son évolutivité automatique, Upsun peut vous aider à gérer les hausses de trafic en douceur. Il fournit également des outils de surveillance et de sécurité et vous permet de gérer plusieurs applications ou microservices dans différents langages au sein d'un même projet. Ainsi, vous pouvez vous concentrer sur la construction de votre application React pendant qu'Upsun s'occupe de l'infrastructure de base.