Dans cet article, nous aborderons le Virtual DOM et la Réconciliation qui sont des notions peu connues des développeurs ReactJS, mais qui pourtant composent le cœur de leur outil. Je vous définirez ces concepts et vous les illustrerez à l’aide d’exemple afin de lever le brouillard une bonne fois pour toutes!
Introduction
Nombreux sont ceux qui pensent que le secret de la réussite de ReactJS réside dans le fait qu’il utilise le Virtual DOM et que ce dernier lui confère une rapidité supérieure au DOM! En réalité, ça n’est pas tout à fait vrai. Au grand regret de vous décevoir, React n’est pas “plus” rapide que le DOM. Cela reviendrait à dire qu’il est possible d’aller plus vite que la vitesse de la lumière. Regardons de plus prêt la raison pour laquelle React utilise le Virtual DOM.
Je vous rassure d’avance, si vous ne comprenez pas toutes les notions abordées dans cet article du premier coup, c’est normal. Nous allons entrer dans les entrailles de la bête ReactJS afin d’en comprendre son fonctionnement. Prêt à me suivre ? Alors prenez vos lampes torches et allons éclaircir le Virtual DOM et la Réconciliation!
Virtual DOM
Il ne faut pas confondre le DOM et le Virtual DOM. Le DOM est une représentation de la structure et du contenu d’une page web. Le navigateur peut manipuler le DOM afin de modifier l’affichage d’une page. En revanche, le Virtual DOM n’est qu’une copie du DOM sous forme d’objet JavaScript.
ReactJS est une libraire qui est construite sur le principe de State Driven UI (ou interface utilisateur dirigée par les états en bon français). Le changement d’état d’un composant entraîne un re-render de l’interface utilisateur. Le composant ainsi que tous ses enfants sont alors re-render par le DOM. Dépendamment du nombre d’opérations effectuées par le DOM, cette étape peut être très coûteuse ce qui implique de mauvaises performances.
En réalité, React ne va pas demander au DOM de re-render l’intégralité de l’interface utilisateur, il va faire appel au Virtual DOM. Le véritable but du Virtual DOM est de minimiser le nombre d’opérations que le DOM doit réaliser.
Le Virtual DOM a ainsi deux bénéfices :
- Il améliore l’UX (expérience utilisateur) en améliorant les performances de l’application.
- Il améliore la DX (expérience développeur) en créant une abstraction dans la manipulation du DOM, permettant de se soucier des problématiques métier et non des problématiques de gestion du DOM. Pas besoin de se casser la tête à gérer les changements d’état, c’est React qui s’en charge.
Maintenant que nous avons vu ce qu’est le Virtual DOM en théorie passons à la pratique.
Fonctionnement du Virtual DOM dans ReactJS
Comme dis précédemment, le Virtual DOM est un objet JavaScript. Mais à quoi ressemble-t-il ?
Prenons comme exemple le code React suivant :
export default function Counter() {
const [count, setCount] = useState(0);
return (
<>
<p>Ceci est un compteur</p>
<button onClick={() => setCount((count) => count + 1)}>
Total : {count}
</button>
</>
)
}
Ce code représente l’interface ci-dessous :
Vous avez un composant constitué d’un fragment React avec un paragraphe et un bouton. Lorsque vous cliquez sur le bouton, le compteur s’incrémente.
Il est possible de voir le code ci-dessus comme ceci :
const element = React.createElement(
React.Fragment,
null,
React.createElement("p", null, "Ceci est un compteur"),
React.createElement("button", null, "Total : 11"),
)
Et voilà à quoi ressemble le Virtual DOM :
J’attire votre attention sur l’attribut typeoff de l’objet ci-dessus :
$$typeof: Symbol(react.element)
En React, tout élément constituant le DOM est un React Element. Ce sont ces éléments qui sont placés dans le Virtual DOM.
On a donc un arbre (le Virtual DOM) qui est composé de nœuds (React Element). Si vous avez déjà creusé le sujet, vous savez certainement qu’en réalité, les nœuds ne sont pas vraiment des React Element à proprement parler mais des fibers. Pour des soucis de simplification nous diront React Element ici.
Maintenant nous savons ce qu’est le Virtual DOM, à quoi il ressemble, mais on ne sait pas vraiment comment il est utilisé dans ReactJS.
Stratégie d’optimisation de ReactJS
Nous l’avons dit, le Virtual DOM n’est pas une fonctionnalité de React. Il est plutôt un outil permettant de mettre en place la stratégie d’optimisation.
Regardons comment fonctionne le procédé de mise à jour de l’interface utilisateur. Il y a deux opérations possibles. Soit on initialise, soit on met à jour.
L’initialisation
Lors du premier render, React créé l’arbre du Virtual DOM représentant l’interface utilisateur et le stock en mémoire.
Dans notre exemple, on aura donc l’arbre suivant :
La mise à jour
Lorsqu’un état change dans l’un des React Element, une autre version du Virtual DOM est créé. On se retrouve donc avec le current tree qui est l’ancienne version en mémoire et l’updating tree qui est l’arbre avec les mises à jour demandées.
Dans l’exemple précédent, lorsque l’on clique sur le bouton, on incrémente le compteur “count”. Une nouvelle version de l’arbre est donc générée avec le texte du bouton mis à jour.
ReactJS peut ainsi avoir une représentation de l’interface utilisateur avec son état actuel et l’état après les changements demandés par l’utilisateur. Très bien me diriez-vous, React a deux arbres en mémoire, mais comment fait-il pour mettre à jour le DOM?
La réponse est simple, React va faire appel à l’étape de Réconciliation. Mais si, vous vous souvenez du mot qui ne vous parlait pas trop en introduction ! Je m’excuse d’avoir fait durer le suspense aussi longtemps alors sans plus tarder, Mesdames et Messieurs veuillez faire place à l’étape de Réconciliation.
Réconciliation
La réconciliation est l’étape qui consiste à détecter les changements de l’interface utilisateur et de les appliquer sur le DOM. Comme nous l’avons vu, React créé une deuxième représentation virtuel de l’interface après modification. Ce qu’il faut garder en tête c’est que le Virtual DOM n’est à aucun moment une représentation réelle et rien n’est affiché à l’écran. React a juste deux représentations en mémoire de l’état de l’interface. Il faut donc que React détecte de façon précise les éléments qui ont été impactés par les modifications. Pour cela, React utilise un algorithme de comparaison.
L’algorithme de comparaison
Cet algorithme prend deux arbres (current tree et updating tree) et applique de façon récursive le traitement suivant sur les deux arbres :
Une fois que l’algorithme est passé sur tous les noeuds, React connaît les changements entre les deux représentations virtuelles du DOM.
Application des changements dans le DOM
Après l’algorithme de comparaison, React possède une liste de changement à réaliser pour transformer le DOM. React utilise la librairie React DOM pour appliquer ces changements sur le DOM React Dom NPM.
Avant la v16, l’étape de réconciliation utilisait le Stack Reconcilier. Le principe est simple, chacun des changements d’état est placé dans une pile les uns à la suite des autres. Une fois que la pile a fini d’être remplis, on vient appliquer les actions pour chaque changement en les dépilant. Ce procédé se fait de façon synchrone et pose de nombreux problèmes de performances et fluidités, détériorant ainsi l’expérience utilisateur.
Pour améliorer cela, lors de la v16, React a refacto ce système et à proposé la solution du Fiber Algorithme.
Grâce au Fiber Algorithme, les changements à réaliser dans l’interface utilisateur ne sont plus fait de façon synchrone mais asynchrone. Chaque modification est vue comme une unité de travail, avec un état et une priorité. Toutes les unités de travail peuvent être interrompues, reprises ou encore annulées. React peut ainsi prioriser les changements importants et mettre en second plan ceux qui le sont moins.
Si vous voulez découvrir les profondeurs de l’algorithme Fiber, je vous suggère de lire les articles suivants :
Conclusion
Après la lecture de cet article, vous devriez avoir une meilleure vision du Virtual DOM ainsi que la Réconciliation qui sont deux concepts qui se cachent derrière React. Nous avons plongé dans les entrailles de la librairie afin d’en comprendre son fonctionnement.
Ainsi, nous avons vu que le Virtual DOM n’est pas une fonctionnalité, mais bel et bien un outil sur lequel ReactJS s’appuie pour mettre en place sa stratégie de mise à jour du DOM. Le Virtual DOM permet de manipuler des objets et non le DOM directement. Ainsi, React peut optimiser le nombre d’action à réaliser dans le DOM. Couplées à l’étape de Réconciliation, nous obtenons une manière très efficace de faire beaucoup d’action dans l’interface utilisateur de façon optimale.
Nous avons également vu que le Virtual DOM est vital à React car c’est une librairie dite State Driven UI. ReactJS n’est pas plus rapide que le DOM, mais il est très bien optimisé pour une librairie de ce type, ce qui en fait toute sa renommée!
Grâce au Virtual DOM React nous offre la possibilité de nous concentrer sur ce qui compte vraiment, l’expérience utilisateur, au lieu de se concentrer sur des détails techniques tels que la mise à jour du DOM.
Le secret de ReactJS, c’est de nous offre un doux mélange entre une DX de qualité et une UX optimisée.