React, l'un des framework d'interface utilisateur les plus populaires et les plus utilisés, alimente certains grands noms du web comme Netflix, Airbnb, Discord et bien sûr, le berceau de React, Meta (Facebook, Instagram et Whatsapp). Étant donné que React est utilisé pour créer des interfaces utilisateur qui sont utilisées par des milliards de personnes, il est raisonnable de supposer qu'une part non négligeable de tout le trafic internet est « gérée » par React.
En début d'année, la très attendue React 19 a été annoncée, mais avec toutes les nouvelles fonctionnalités brillantes et les améliorations DX, il y avait un petit changement qui est passé inaperçu jusqu'à la semaine dernière et qui pourrait potentiellement dégrader de manière significative la performance de nombreux sites web qui s'appuient sur React.
Tout a commencé par ce post sur X de Dominik, alias TkDodo, l'un des principaux mainteneurs de TanStack Query :
Code React : | Sélectionner tout |
1 2 3 4 | <Suspense fallback={<p>...</p>}> <RepoData name="tanstack/query" /> <RepoData name="tanstack/table" /> </Suspense> |
Ceci lance deux requêtes en parallèle, attend que les deux soient résolues et affiche ensuite le sous-arbre entier.
Dans React 19, pour autant que je sache, les requêtes sont maintenant exécutées en cascade. Je crois me souvenir que @rickhanlonii avait mentionné quelque chose de ce genre, mais je n'ai pas trouvé de preuve maintenant.
Am I imagining things or is there a difference between React 18 and 19 in terms of how Suspense handles parallel fetching? In 18, there is a "per component" split, so putting two components into the same Suspense Boundary, where each was doing a fetch, was still firing them in…
— Dominik 🔮 (@TkDodo) June 11, 2024
Pour mémoire, React Suspense est une fonctionnalité introduite dans React 16.6 qui permet de « suspendre » le rendu de l’arbre de composants jusqu’à ce qu’une certaine condition soit remplie, généralement utilisée pour gérer la récupération de données de manière déclarative. Elle améliore l’expérience utilisateur en évitant l’affichage de contenu incomplet ou vide en attendant que les données soient chargées. Suspense utilise une approche déclarative pour la gestion des opérations asynchrones comme la récupération de données ou le fractionnement de code, et permet d’afficher un contenu de repli ou des indications de chargement pendant que les données sont en cours de chargement. C’est une partie importante de la construction d’applications React plus réactives et efficaces.
Les propos de TkDodo ont entraîné des réactions comme celle d'Adam Rackis :
Le pire dans tout cela, c'est que bien qu'il s'agisse d'un changement radical en termes de performances qui va affecter de nombreuses personnes qui dépendent de ce modèle, il n'y a qu'une seule ligne dans une liste à puces qui mentionne sans cérémonie ce changement :This is a maddening, incomprehensible change. From the comments it _seems like_ this applies to client components, but parallel fetches still work in RSC
— Adam Rackis (@AdamRackis) June 11, 2024
Which wrecks react-query, the one good way of managing data with React.
I hope cooler heads prevail but I’m sure they won’t. https://t.co/6QcJeLmOXt
Récapitulatif de Suspense
Pour comprendre de quoi il s'agit, il faut d'abord faire un petit récapitulatif sur Suspense de React. Suspense est un composant React qui vous permet d'afficher un fallback jusqu'à ce que ses enfants aient fini de se charger, soit parce que ces composants enfants sont chargés paresseusement, soit parce qu'ils utilisent un mécanisme de récupération de données activé par Suspense.
Il s'utilise de la manière suivante :
Code React : | Sélectionner tout |
1 2 3 | <Suspense fallback={<Loading />}> <ComponentThatFetchesDataOrIsLazyLoaded /> </Suspense> |
Bien que Suspense fasse partie de l'API de React depuis un certain temps maintenant, pendant longtemps, la seule utilisation officiellement approuvée était de charger paresseusement des composants avec React.lazy, ce qui est extrêmement utile pour diviser le code de votre application et ne charger que les parties divisées lorsque c'est nécessaire.
Lorsqu'il est utilisé avec React.lazy, en essayant de rendre le composant chargé paresseusement pour la première fois (c'est-à-dire avant de le charger paresseusement), il déclenche la limite de Suspense (c'est-à-dire le Suspense enveloppant le composant) et rend le fallback jusqu'à ce que la récupération du code du composant soit terminée, puis il rend le composant lui-même.
Pendant longtemps, les développeurs ont attendu un support officiel de Suspense pour la récupération de données sur le client (cela fonctionne déjà sur le serveur en utilisant les RSC), mais ils ont du attendre longtemps et, malgré cela, beaucoup de bibliothèques (TanStack Query étant l'une d'entre elles) l'ont implémenté en explorant les internes de React. Pour cette raison, il y a beaucoup d'applications en production qui utilisent actuellement Suspense pour la récupération de données sur le client.
Comprendre le changement
En clair, React 19 désactive le rendu parallèle des frères à l'intérieur de la même frontière Suspense, ce qui introduit essentiellement des chutes de données pour les données qui sont récupérées à l'intérieur de ces frères.
Voici un exemple qui illustre cette idée :
Code React : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function App() { return ( <> <Suspense fallback={"Loading..."}> <ComponentThatFetchesData val={1} /> <ComponentThatFetchesData val={2} /> <ComponentThatFetchesData val={3} /> </Suspense> </> ); } const ComponentThatFetchesData = ({ val }) => { const result = fetchSomethingSuspense(val); return <div>{result}</div>; }; |
Demo : https://stackblitz.com/edit/vitejs-v...=src%2FApp.jsx
Dans cet exemple (dans React 18), même si fetchSomethingSuspense provoque la suspension du premier ComponentThatFetchesData, React essaiera toujours de rendre ses frères, ce qui déclenchera la collecte de données pour chacun d'entre eux en parallèle.
Cela peut être vu en regardant la console où sont enregistré le moment où chaque récupération de données a été déclenchée :
Toutes les données sont récupérées presque au même moment.
Regardons maintenant ce qui se passe lorsque nous exécutons exactement le même code dans React 19 (canary) :
Demo: https://stackblitz.com/edit/vitejs-v...=src%2FApp.jsx
Lorsque nous regardons à nouveau la console, nous remarquons qu'il y a maintenant une différence, car chaque récupération de données ne démarre qu'après que la précédente ait été achevée.
Ceci est dû au PR suivant : https://github.com/facebook/react/pull/26380
Les conséquences
Heureusement, cette histoire se termine bien. Après de nombreuses réactions publiques, des discussions animées et probablement beaucoup de discussions en coulisses, l'équipe React a fait marche arrière et a décidé de suspendre ce changement pour l'instant.
- Nous nous intéressons beaucoup aux SPA, mais l'équipe a mal évalué le nombre de personnes qui s'en servent aujourd'hui.
- Nous recommandons toujours le préchargement, mais nous reconnaissons que ce n'est pas toujours pratique.
- Nous prévoyons de retarder la sortie de la version 19.0 jusqu'à ce que nous trouvions un bon correctif
Plus d'informations à venir
Conclusiongood news re Suspense, just met w/ @rickhanlonii @en_JS @acdlite
— sophie alpert (@sophiebits) June 14, 2024
* we care a lot about SPAs, team misjudged how many people rely on this today
* still recommend preloading but recognize not always practical
* we plan to hold the 19.0 release until we find a good fix
more to come
Ce n'est pas la première fois que la communauté s'oppose à des changements introduits dans React sans tenir compte de la façon dont React est utilisé en dehors de Meta et Vercel. Il est clair qu'il y a un décalage entre ce que les mainteneurs de React pensent être le meilleur pour l'avenir de React et les opinions de la communauté sur le sujet.
La controverse entourant React 19 souligne le défi constant auquel sont confrontés les développeurs : équilibrer l’adoption de nouvelles technologies avec la maintenance de la stabilité des applications existantes. Alors que React continue d’évoluer, il est essentiel que la communauté collabore pour surmonter ces défis et tirer le meilleur parti des avancées technologiques.
Source : Henrique Yuji
Et vous ?
Quel impact pensez-vous que React 19 aura sur l’expérience utilisateur des sites web à grande échelle ?
Comment les développeurs peuvent-ils s’assurer que les mises à jour des frameworks comme React n’affectent pas négativement la performance des sites web ?
Quelles mesures préventives peuvent être prises pour éviter les ralentissements potentiels dus aux mises à jour technologiques ?
En tant qu’utilisateur, avez-vous remarqué des changements dans la vitesse de chargement des sites web depuis la mise à jour React 19 ?
Quelle est l’importance de l’équilibre entre l’innovation technologique et la stabilité de performance dans le développement web ?