Kodokon kodokon.com

Unter der Haube: Reconciliation, Batching, Concurrent Rendering

Entdecke, wie Fiber den Baum abgleicht, Updates bündelt und die Render-Arbeit unterbrechbar macht.

11 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Seit React 16 heißt die interne Engine Fiber: Jedes Element in deinem Baum wird durch einen Fiber-Knoten dargestellt, eine Arbeitseinheit. React verwaltet in Wirklichkeit zwei Bäume (eine Double-Buffering-Technik): den current-Baum, der widerspiegelt, was auf dem Bildschirm ist, und den workInProgress-Baum, der während des Renderings aufgebaut wird. Die Arbeit läuft in zwei getrennten Phasen ab: die Render-Phase (Aufruf deiner Komponenten, Berechnung der Unterschiede), die unterbrechbar und wiederholbar ist, dann die Commit-Phase (Anwenden der Mutationen auf das DOM, Ausführen der Effekte), die immer synchron und unterbrechungsfrei ist. Reconciliation stützt sich auf zwei Heuristiken, die den Vergleich auf lineare Kosten senken: Ändert sich der Typ eines Elements an einer bestimmten Position, zerstört React den gesamten Teilbaum und baut ihn neu auf, samt State; bei Listen ermöglicht die key-Prop React, Elemente zwischen zwei Renders einander zuzuordnen.

JSX
function List({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>
          <input defaultValue={item.label} />
        </li>
      ))}
    </ul>
  );
}
// With key={index}, deleting the first item
// would shift the content of the remaining inputs.
Ein stabiler Key bewahrt State und DOM jeder Zeile.

Der zweite grundlegende Mechanismus: Batching. Wenn mehrere State-Updates im selben Kontext ausgelöst werden, fasst React sie zu einem einzigen Render zusammen. Vor React 18 funktionierte diese Bündelung nur innerhalb von React-Event-Handlern; seit createRoot läuft sie überall automatisch: Timer, Promises, native Listener. Deshalb liefert das Lesen des States direkt nach einem setState auch den alten Wert: Das Update ist eingeplant, nicht angewendet.

JSX
function handleTick() {
  setCount((c) => c + 1);
  setFlag((f) => !f);
  // React 18: a single render, even here.
}

setTimeout(handleTick, 100);
// Before React 18, this timer would trigger
// two successive renders.
Automatisches Batching deckt jetzt jeden Kontext ab.

Concurrent Rendering treibt die Logik weiter: Die Render-Phase kann unterbrochen, fortgesetzt oder sogar verworfen und neu gestartet werden, wenn ein dringenderes Update eintrifft. React ordnet Updates nach Priorität (den Lanes): Ein Tastendruck ist dringend, ein mit startTransition markierter Listenfilter nicht. Die unmittelbare Folge: Deine Komponentenfunktionen müssen rein sein, denn React ruft sie unter Umständen mehrmals auf, ohne das Ergebnis je zu committen. Ein weiterer Grenzfall: Ein externer Store (Redux, Zustand, ein selbstgebautes Singleton), der während eines unterbrechbaren Renders gelesen wird, kann sich mitten im Render ändern und eine inkonsistente Oberfläche erzeugen, bekannt als Tearing. Die useSyncExternalStore-API löst dieses Problem, indem sie bei einer Änderung des Stores einen synchronen Render erzwingt.

JAVASCRIPT
import { useSyncExternalStore } from 'react';

function useWindowWidth() {
  return useSyncExternalStore(
    (notify) => {
      window.addEventListener('resize', notify);
      return () =>
        window.removeEventListener('resize', notify);
    },
    () => window.innerWidth
  );
}
Einen externen Store lesen, ohne Risiko von Tearing.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Was macht React während der Reconciliation, wenn ein <div>-Element an derselben Position zu einem <span> wird?
    • Es aktualisiert das Tag und behält die Kinder
    • Es zerstört den gesamten Teilbaum samt State und baut ihn neu auf
    • Es vergleicht rekursiv die Kinder, bevor es entscheidet
    • Es wirft einen Reconciliation-Fehler
  2. Wie viele Renders lösen mit React 18 und createRoot zwei setState-Aufrufe innerhalb eines setTimeout aus?
    • Zwei, weil Batching nur für React-Events gilt
    • Nur einen, dank des automatischen Batchings
    • Keinen, Updates außerhalb von Events werden ignoriert
  3. Welche Phase der Arbeit von React ist im Concurrent-Modus unterbrechbar?
    • Nur die Commit-Phase
    • Nur die Render-Phase
    • Beide Phasen
    • Keine, React bleibt vollständig synchron