React v16.0

September 26, 2017 par Andrew Clark

Nous sommes ravis d’annoncer la sortie de React v16.0 ! On y trouve notamment quelques fonctionnalités attendues de longue date, telles que les fragments, les périmètres d’erreurs, les portails, la prise en charge des attributs DOM personnalisés, un rendu côté serveur amélioré et une taille de fichier réduite.

Nouveaux types de retour pour render : fragments et chaînes

Vous pouvez désormais renvoyer un tableau d’éléments depuis la méthode render d’un composant. Comme pour tous les tableaux, vous devrez ajouter une prop key à chaque élément afin d’éviter l’avertissement associé :

render() {
  // Pas besoin d’enrober cette liste par un élément dédié !
  return [
    // Mais n’oubliez pas les clés :)
    <li key="A">Premier élément</li>,
    <li key="B">Deuxième élément</li>,
    <li key="C">Troisième élément</li>,
  ];
}

À partir de React 16.2.0, nous ajouterons la prise en charge d’une syntaxe spéciale de fragments dans JSX, qui n’exigera pas de clés.

Nous avons aussi ajouté la possibilité de renvoyer des chaînes de caractères :

render() {
  return 'Regarde maman, sans les spans !';
}

Consultez la liste intégrale des types de retour autorisés.

Meilleure gestion des erreurs

Jusque-là, les erreurs à l’exécution lors du rendu pouvaient laisser React dans un état bancal, entraînant des messages d’erreurs cryptiques et nécessitant un rafraîchissement de la page pour revenir à la normale. Pour y remédier, React 16 utilise une stratégie de gestion d’erreurs plus robuste. Par défaut, lorsqu’une erreur est levée au sein du rendu d’un composant ou d’une de ses méthodes de cycle de vie, l’arborescence de composants complète est démontée de la racine. On évite ainsi d’afficher des données corrompues. Cependant, ça ne constitue pas une expérience utilisateur idéale.

Au lieu de démonter l’appli entière à chaque fois qu’une erreur survient, vous pouvez recourir aux périmètres d’erreurs. Les périmètres d’erreurs sont des composants spéciaux qui capturent les erreurs survenant dans leur sous-arbre, et affichent alors une interface utilisateur (UI) de repli. Vous pouvez considérer les périmètres d’erreurs comme des instructions try-catch, mais pour les composants React.

Pour en apprendre davantage, jetez un coup d’œil à notre précédent article sur la gestion d’erreurs avec React 16.

Portails

Les portails fournissent un moyen officiel d’afficher des enfants dans un nœud DOM situé hors de la hiérarchie DOM du composant parent.

render() {
  // React *ne crée pas* une nouvelle div.  Il affiche les enfants dans `domNode`.
  // `domNode` peut être n’importe quel nœud DOM valide, où qu’il soit dans le DOM.
  return ReactDOM.createPortal(
    this.props.children,
    domNode,
  );
}

Vous pouvez consulter un exemple complet dans la documentation des portails.

Meilleur rendu côté serveur

React 16 inclut un moteur de rendu côté serveur (Server-side rendering ou SSR, NdT) intégralement réécrit. Il est très rapide. Il prend en charge le streaming, ce qui vous permet de commencer à envoyer du contenu à votre client plus tôt. Et grâce à notre nouvelle stratégie de packaging qui précompile les vérifications basées sur process.env (figurez-vous que lire process.env dans Node.js est super lent !), vous n’avez plus besoin de bundler React pour obtenir de bonnes performances de rendu côté serveur.

Sasha Aickin, membre de l’équipe noyau de React, a écrit un super article au sujet des améliorations du SSR dans React 16 (en anglais). Selon ses méthodes de mesure, le rendu côté serveur avec React 16 est à peu près trois fois plus rapide qu’avec React 15. « Lorsqu’on compare avec React 15 qui précompilerait les lectures de process.env, on constate une accélération d’environ 2,4x avec Node 4, de 3x avec Node 6, et carrément de 3,8x avec la nouvelle version 8.4 de Node. Et si vous comparez avec React 15 sans précompilation, React 16 accélère par un ordre de magnitude le SSR avec la dernière version de Node ! » (Comme le fait remarquer Sasha, gardez à l’esprit que ces chiffres sont basés sur des mesures de situations artificielles, et que vous pourriez avoir des résultats différents sur des applications réelles.)

Qui plus est, React 16 hydrate mieux le HTML rendu côté serveur lorsque celui-ci atteint le client. Il n’exige plus que le rendu initial client corresponde exactement à celui issu du serveur. Au lieu de ça, il essaiera de réutiliser au maximum le DOM existant. Plus de sommes de contrôle ! D’une façon générale, nous déconseillons de faire des rendus distincts entre serveur et client, mais ça peut s’avérer utile dans certains cas (ex. les horodatages). Il est toutefois dangereux d’avoir des nœuds manquants côté serveur, car ça pourrait entraîner la création de nœuds aux attributs incorrects au même niveau du DOM.

Consultez la documentation de ReactDOMServer pour en apprendre davantage.

Prise en charge des attributs DOM personnalisés

Au lieu d’ignorer les attributs HTML et SVG non reconnnus, React les transfèrera désormais au DOM. Ça présente l’avantage supplémentaire de permettre la purge de l’essentiel de la liste blanche d’attributs de React, ce qui réduit au passage les tailles des fichiers.

Taille de fichier réduite

En dépit de toutes ces nouveautés, React 16 est en fait plus petit que la 15.6.1 !

  • react fait 5.3 Ko (2.2 Ko gzippé), au lieu de 20.7 Ko (6.9 Ko gzipped).
  • react-dom fait 103.7 Ko (32.6 Ko gzippé), au lieu de 141 Ko (42.9 Ko gzippé).
  • react + react-dom font 109 Ko (34.8 Ko gzippé), au lieu de 161.7 Ko (49.8 Ko gzippé).

Ça correspond au total à une réduction de 32% de la taille, comparé à la version précédente (30% après gzip).

Cette différence de taille est en partie attribuable à des changements de stratégie de packaging. React utilise désormais Rollup pour créer des bundles plats pour chaque type de distribution, ce qui à la fois réduit la taille et améliore les performances d’exécution. Ce format à plat permet aussi à React d’impacter de façon similaire la taille de votre bundle, indépendamment de la façon dont vous livrez votre propre appli, que vous utilisiez Webpack, Browserify, les bundles UMD officiels, ou tout autre mécanisme.

Licence MIT

Au cas où vous l’auriez raté, React 16 est désormais disponible sous licence MIT. Nous avons également publié la 15.6.2 sous MIT, pour celles et ceux qui ne peuvent pas mettre à jour immédiatement.

Nouvelle architecture du noyau

React 16 est la première version de React basée sur notre nouvelle architecture noyau, dont le nom de code est “Fiber”. Vous pouvez tout savoir sur ce projet en consultant le blog d’ingénierie de Facebook. (Divulgâcheur : nous avons réécrit React !)

Fiber est responsable de la plupart des nouveautés de React 16, telles que les périmètres d’erreurs et les fragments. Dans les prochaines versions, attendez-vous à davantage de nouvelles fonctionnalités tandis que nous continuerons à libérer davantage le véritable potentiel de React.

Le domaine le plus enthousiasmant sur lequel nous travaillons est sans doute le rendu asynchrone, une stratégie de planification coopérative du travail de rendu qui permet de rendre périodiquement la main au navigateur. Le principal avantage, avec le rendu asynchrone, c’est que les applis deviennent plus réactives, car React évite de bloquer le thread principal.

La démo ci-dessous fournit un premier aperçu des types de problématiques que résout le rendu asynchrone :

Astuce : soyez attentif·ve au carré noir qui tourne.

Nous estimons que le rendu asynchrone sera très important, et représente l’avenir de React. Pour faciliter autant que possible la migration vers la v16.0, nous n’activons pas encore les fonctionnalités asynchrones, mais nous avons hâte de commencer à les rendre disponibles au cours des prochains mois. Restez à l’écoute !

Installation

React v16.0.0 est disponible sur le référentiel npm.

Pour installer React 16 avec Yarn, exécutez :

yarn add react@^16.0.0 react-dom@^16.0.0

Pour installer React 16 avec npm, exécutez :

npm install --save react@^16.0.0 react-dom@^16.0.0

Nous fournissons aussi des builds UMD de React via un CDN :

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Consultez la documentation pour des instructions d’installation détaillées.

Mise à jour

Bien que React 16 inclue des modifications internes majeures, en termes de mise à jour, vous pouvez la considérer comme n’importe quelle autre version majeure de React. Nous utilisons React 16 sur Facebook et Messenger.com depuis plus tôt cette année, et avons pu tirer parti de plusieurs versions beta et candidates pour éliminer des problèmes résiduels. À de rares exceptions près, si votre appli fonctionne avec React 15.6 sans avertissements, elle devrait marcher avec la 16.

Pour les dépréciations listées dans Packaging ci-après, des codemods (outils de migration automatique du code) sont fournis qui transformeront automatiquement votre code déprécié. Consultez l’article sur la 15.5.0 pour en apprendre davantage, ou parcourez les codemods disponibles sur le projet react-codemod.

Nouvelles dépréciations

Hydrater un conteneur rendu côté serveur nécessite désormais une API explicite. Si vous dynamisez du HTML rendu côté serveur, utilisez ReactDOM.hydrate au lieu de ReactDOM.render. Continuez à utiliser ReactDOM.render si vous faites uniquement le rendu côté client.

React Addons

Comme annoncé précédemment, nous avons cessé de prendre en charge React Addons. Nous estimons que la dernière version en date de chaque addon (à l’exception de react-addons-perf, voir plus loin) devrait continuer à fonctionner dans un avenir proche, mais nous ne les maintiendrons plus.

Consultez l’annonce précédente pour y trouver des suggestions de migration.

react-addons-perf ne fonctionne plus du tout avec React 16. Il est probable que nous en publierons une nouvelle version à l’avenir. Dans l’intervalle, vous pouvez utiliser les outils de performance de votre navigateur pour profiler vos composants React.

Ruptures de compatibilité ascendante

React 16 comporte quelques petites ruptures de compatibilité. Elles concernent uniquement des cas à la marge et ne devraient pas impacter la majorité des applis.

  • React 15 avait une prise en charge partielle et non documentée des périmètres d’erreurs au travers de unstable_handleError. Cette méthode a été renommée componentDidCatch. Vous pouvez utiliser un codemod pour migrer automatiquement vers la nouvelle API.
  • ReactDOM.render et ReactDOM.unstable_renderSubtreeIntoContainer renvoient désormaient null si on les appelle depuis une méthode de cycle de vie. Pour contourner ça, vous pouvez recourir aux portails ou aux refs.
  • setState:

    • Appeler setState avec null ne déclenche plus de mise à jour. Ça vous permet de décider dans une fonction de mise à jour si vous souhaitez déclencher un rendu ou non.
    • Appeler setState directement depuis render entraîne systématiquement une mise à jour. Ce n’était pas toujours le cas par le passé. Quoi qu’il en soit, vous ne devriez pas appeler setState depuis render.
    • Les fonctions de rappel de setState (son second argument) sont désormais déclenchées immédiatement après componentDidMount / componentDidUpdate, plutôt qu’après le rendu de l’ensemble des composants.
  • Si React remplace <A /> par <B />, B.componentWillMount aura toujours lieu avant A.componentWillUnmount. Auparavant, A.componentWillUnmount était appelé en premier dans certains cas.
  • Jusqu’ici, modifier la ref d’un composant en détachait toujours la ref avant que le render du composant soit appelé. Nous ajustons désormais la ref plus tard, en appliquant les modifications au DOM.
  • Il est dangereux de refaire un rendu dans un conteneur qui a été modifié par autre chose que React. Ça fonctionnait jusqu’ici dans certains cas, mais restait totalement officieux. Nous émettons désormais un avertissement dans un tel cas. Vous devriez plutôt nettoyer les arborescences DOM de vos composants à l’aide de ReactDOM.unmountComponentAtNode. En voici un exemple.
  • La méthode de cycle de vie componentDidUpdate ne reçoit plus le paramètre prevContext. (Voir #8631.)
  • Le moteur de rendu superficiel n’appelle plus componentDidUpdate parce que les refs DOM n’y sont pas disponibles. On est désormais cohérents avec componentDidMount (qui n’était pas appelé non plus dans les anciennes versions).
  • Le moteur de rendu superficiel n’implémente plus unstable_batchedUpdates.
  • ReactDOM.unstable_batchedUpdates n’accepte plus qu’un argument supplémentaire après la fonction de rappel.

Packaging

  • On ne trouve plus react/lib/* et react-dom/lib/*. Même dans les environnements CommonJS, React et ReactDOM sont précompilés vers des fichiers uniques (« bundles à plat »). Si vous vous reposiez jusque-là sur des éléments internes non documentés de React, et que ces aspects ne fonctionnent plus, créez un ticket spécifique pour nous en parler, et nous verrons si nous pouvons vous proposer une stratégie de migration.
  • Il n’y a plus de build react-with-addons.js. Tous les addons compatibles sont publiés séparément sur npm, et fournissent des fichiers uniques pour leurs versions navigateur si vous en avez besoin.
  • Les dépréciations introduites dans les versions 15.x ont été retirées du paquet noyau. React.createClass est désormais disponible dans create-react-class, React.PropTypes dans prop-types, React.DOM dans react-dom-factories, react-addons-test-utils dans react-dom/test-utils, et le moteur de rendu superficiel dans react-test-renderer/shallow. Consultez les articles de 15.5.0 et 15.6.0 pour apprendre comment migrer votre code à l’aide de codemods automatisés.
  • Les noms et chemins des builds navigateurs mono-fichier ont changé pour accentuer la distinction entre les builds de développement et ceux de production. Par exemple :

    • react/dist/react.jsreact/umd/react.development.js
    • react/dist/react.min.jsreact/umd/react.production.min.js
    • react-dom/dist/react-dom.jsreact-dom/umd/react-dom.development.js
    • react-dom/dist/react-dom.min.js → react-dom/umd/react-dom.production.min.js

Exigences vis-à-vis de l’environnement JavaScript

React 16 requiert les types de collections natifs Map et Set. Si vous prenez en charge des navigateurs et périphériques plus anciens qui pourraient ne pas les fournir nativement (par exemple IE < 11), envisagez l’inclusion d’un polyfill global dans votre application bundlée, tel que core-js ou babel-polyfill.

Un environnement polyfillé pour React 16 utilisant core-js pour autoriser des navigateurs plus anciens pourrait ressembler à ceci :

import 'core-js/es6/map';
import 'core-js/es6/set';

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Bonjour, monde !</h1>,
  document.getElementById('root')
);

React utilise aussi requestAnimationFrame (même dans les environnements de test). Vous pouvez utiliser le module raf pour simuler requestAnimationFrame :

import 'raf/polyfill';

Remerciements

Comme toujours, cette version n’aurait pas été possible sans nos contributeur·rice·s open source. Un immense merci à toutes les personnes qui ont créé des tickets, ouvert des PR, répondu aux tickets, écrit de la documentation, et plus encore !

Un remerciement tout spécial aux contributeurs noyau, en particulier pour leurs efforts héroïques des dernières semaines en préparation de cette sortie : Brandon Dail, Jason Quense, Nathan Hunzaker, et Sasha Aickin.