Découvrez comment Fiber réconcilie l'arbre, groupe les mises à jour et rend le travail interruptible.
Ouvrir cette leçon dans KodokonDepuis React 16, le moteur interne s'appelle Fiber : chaque élément de votre arbre est représenté par un nœud fiber, une unité de travail. React maintient en réalité deux arbres (technique du double buffering) : l'arbre current, qui reflète ce qui est affiché, et l'arbre workInProgress, construit pendant le rendu. Le travail se déroule en deux phases distinctes : la phase de rendu (appel de vos composants, calcul des différences), interruptible et rejouable, puis la phase de commit (application des mutations au DOM, exécution des effets), toujours synchrone et ininterruptible. La réconciliation repose sur deux heuristiques qui ramènent la comparaison à un coût linéaire : si le type d'un élément change à une position donnée, React détruit tout le sous-arbre et le reconstruit, état compris ; pour les listes, la prop key permet d'apparier les éléments entre deux rendus.
function List({ items }) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>
<input defaultValue={item.label} />
</li>
))}
</ul>
);
}
// Avec key={index}, supprimer le premier item
// decalerait le contenu des inputs restants.Deuxième mécanisme fondamental : le batching. Quand plusieurs mises à jour d'état sont déclenchées dans un même contexte, React les groupe en un seul rendu. Avant React 18, ce regroupement ne fonctionnait que dans les gestionnaires d'événements React ; depuis createRoot, il est automatique partout : timers, promesses, listeners natifs. C'est aussi pourquoi lire l'état juste après un setState renvoie l'ancienne valeur : la mise à jour est planifiée, pas appliquée.
function handleTick() {
setCount((c) => c + 1);
setFlag((f) => !f);
// React 18 : un seul rendu, meme ici.
}
setTimeout(handleTick, 100);
// Avant React 18, ce timer provoquait
// deux rendus successifs.Le rendu concurrent pousse la logique plus loin : la phase de rendu peut être interrompue, reprise, voire jetée et recommencée si une mise à jour plus urgente arrive. React classe les mises à jour par priorité (les lanes) : une frappe clavier est urgente, un filtrage de liste marqué par startTransition ne l'est pas. Conséquence directe : vos fonctions de composant doivent être pures, car React peut les appeler plusieurs fois sans jamais committer le résultat. Autre cas limite : un store externe (Redux, Zustand, un singleton maison) lu pendant un rendu interruptible peut changer en cours de rendu, produisant une interface incohérente appelée tearing. L'API useSyncExternalStore résout ce problème en forçant un rendu synchrone quand le store change.
import { useSyncExternalStore } from 'react';
function useWindowWidth() {
return useSyncExternalStore(
(notify) => {
window.addEventListener('resize', notify);
return () =>
window.removeEventListener('resize', notify);
},
() => window.innerWidth
);
}<div> devient un <span> à la même position ?createRoot, deux appels à setState dans un setTimeout provoquent combien de rendus ?