Startseite / Artikel / Svelte 5 Runes und SolidJS Signals: UI-Updates ohne erneutes Rendern

Svelte 5 Runes und SolidJS Signals: UI-Updates ohne erneutes Rendern

Sehen Sie, wie Svelte 5 Runes kompiliert und SolidJS Signale verbindet, um den DOM direkt zu aktualisieren, wie sich das von React und Angular unterscheidet – und wann ein Wechsel sinnvoll ist.

1774 Wörter

Jeder React-Entwickler muss irgendwann erklären, warum eine Komponente viermal gerendert wird, obwohl sich nichts Sichtbares geändert hat, und warum die Lösung memo, ein Abhängigkeitsarray sowie einen stabilen Callback beinhaltet. Svelte und SolidJS gehen von einer anderen Voraussetzung aus: Wenn das Framework genau weiß, welcher Zustandteil welchen DOM-Node versorgt, kann es diesen einen Node aktualisieren und den Neustart der Komponenten ganz vermeiden. Dieser Artikel erläutert, wie jede dieser Frameworks das erreicht, wie der Code in der Praxis aussieht, wo sich ihr Modell von React und Angular unterscheidet sowie wie man entscheiden kann, ob eines davon in seinem nächsten Projekt verwendet werden sollte.

Der virtuelle DOM war ein Mittel, kein Ziel

Die zentrale Idee von React bei seinem Erscheinen im Jahr 2013 war der virtuelle DOM. Die Benutzeroberfläche wird dabei als Funktion des Zustands beschrieben. Wenn sich der Zustand ändert, ruft React Ihre Komponente erneut auf, erstellt einen neuen In-Memory-Baum, vergleicht ihn mit dem vorherigen und wendet nur die Unterschiede auf den echten DOM an.

Dieses Design machte die Benutzeroberflächen weitaus vorhersehbarer als manuelle DOM-Manipulationen, und es bleibt weiterhin ein solides Modell. Es hat jedoch auch einen Nachteil: Die Komponentenfunktion wird erneut ausgeführt, unabhängig davon, ob sich deren Ausgabe ändern muss; ein neuer Baum wird allokiert und eine Differenzierungsschleife ermittelt, was tatsächlich geändert wurde – all das nur, um im schlimmsten Fall einen einzigen <span> zu aktualisieren. Wenn Sie Details darüber erfahren möchten, was der Reconciler vergleicht und warum, behandelt der Artikel „Wie die Differenzierung im virtuellen DOM funktioniert“ dieses Thema.

Ein Großteil der API von React seitdem – memo, useMemo, useCallback sowie kürzlich der React Compiler – dient dazu, die Arbeiten zu umgehen, die das Render-und-Diff-Modell sonst ausführen würde. Der Compiler automatisiert die Memoisierung, sodass Entwickler weniger davon manuell schreiben müssen, doch das zugrunde liegende Modell bleibt unverändert: Komponenten werden erneut ausgeführt, und Optimierung bedeutet, sie davon abzuhalten. Der Artikel zu was der React Compiler optimiert und was er Ihnen überlässt geht auf diese Grenzen ein.

Svelte und Solid stellen eine einfachere Frage: Was wäre, wenn die Abhängigkeit zwischen jedem Zustandswert und jedem DOM-Node genau bekannt wäre, sodass nur dieser Node bei einem Zustandswechsel beeinflusst wird?

Svelte: Ein Compiler, der den Aktualisierungscode für Sie schreibt

Svelte ist im Wesentlichen ein Compiler. Sie erstellen Komponenten in .svelte-Dateien, und beim Kompilieren wandelt Svelte sie in reines JavaScript um, das den DOM direkt manipuliert. Es gibt keinen virtuellen DOM und keine Laufzeit-Vergleiche, und nur eine kleine Laufzeitumgebung wird an den Browser gesendet.

Seit Svelte 5 wird Reaktivität durch Runes ausgedrückt – explizite Primitive, die der Compiler erkennt. Die untenstehende Komponente deklariert einen Zustand sowie einen daraus abgeleiteten Wert und rendernt beides in einem Button:

<script>
  let count = $state(0);
  let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
  {count} doubled is {doubled}
</button>

Das ist der gesamte Komponenteninhalt. Es gibt weder eine Setter-Funktion noch ein Abhängigkeitsarray. Man erhöht count wie eine gewöhnliche Variable, und da der Compiler bereits analysiert hat, welche Teile des Codes count und doubled lesen, erzeugt er Code, der genau diese Textknoten aktualisiert. $derived wird nur dann neu berechnet, wenn sich etwas ändert, was er liest. Beachten Sie, dass Event-Handler in Svelte 5 reguläre Attribute wie onclick sind, die die ältere Direktivsyntax on:click ersetzen.

Warum Teams es mögen

  • Ohne Hooks, Setter oder Wrapper-Komponenten sind Svelte-Komponenten in der Regel deutlich kürzer als ihre React-Äquivalente. Weniger Code bedeutet in der Regel weniger Stellen für Fehler und schnellere Überprüfungen.
  • Kleine Pakete. Da der größte Teil der Arbeit zur Kompilierzeit stattfindet, ist die Kostenbelastung des Frameworks im Browser gering. Für Inhaltsseiten, Landing Pages und alle Anwendungen, bei denen die erste Ladezeit entscheidend ist, stellt dies einen echten wirtschaftlichen Vorteil dar.
  • Bekannte Web-Bausteine. Markup, skopierte Styles und Skripte befinden sich in einer Datei und lesen sich wie HTML, CSS und JavaScript. Es gibt keine JSX-spezifischen Konventionen wie className, wodurch die Dateien für Designer und Reviewer, die nicht in React programmieren, leicht zugänglich sind.
  • Für vollständige Anwendungen fügt SvelteKit Routing, Server-Rendering und API-Endpunkte hinzu und übernimmt damit die Rolle von Next.js für React – mit dem Ruf, eine einfachere Konfiguration zu erfordern.

    Eine Einschränkung, die man bereits im Voraus kennen sollte: Runen sind Compilerfunktionen, daher funktionieren sie nur innerhalb von .svelte-Dateien sowie in Modulen mit der Endung .svelte.js oder .svelte.ts. Die Verlegung reaktiver Logik in eine einfache .js-Hilfsdatei funktioniert ohne diese Namenskonvention nicht.

    SolidJS: JSX, das nur einmal ausgeführt wird

    Solid lässt sich auf den ersten Blick leicht mit React verwechseln. Es verwendet JSX, es kombiniert kleine Funktionen, und ein Zähler sieht fast identisch aus:

    function Counter() {
      const [count, setCount] = createSignal(0);
      return (
        <button onClick={() => setCount(count() + 1)}>
          Count: {count()}
        </button>
      );
    }
    

    Was React-Entwickler überrascht, ist die Tatsache, dass Counter genau einmal ausgeführt wird. Solid basiert hingegen auf fein abgestimmter Reaktivität mittels Signalen. createSignal gibt einen Getter und einen Setter zurück, wobei der Getter count() eine Funktionsaufruf ist und keine einfache Wert. Wenn JSX count() innerhalb einer Expression liest, protokolliert Solid, dass dieser spezielle Textknoten von diesem Signal abhängt. Der spätere Aufruf von setCount aktualisiert lediglich diesen Textknoten und nichts anderes. Die Komponentenfunktion diente lediglich als Einrichtungsschritt, um Signale mit DOM-Elementen zu verbinden; sie wird danach nicht mehr ausgeführt, sodass es nichts gibt, was neu gerendert werden müsste.

    Dieses Modell ist der Grund dafür, dass Solid in gängigen Framework-Benchmarks auf dem oberen Niveau abschneidet – oft nahe an handgeschriebenem, reinem JavaScript. Betrachten Sie jede Benchmark-Rangliste lediglich als Momentaufnahme und messen Sie Ihre eigenen Arbeitslasten, doch der architektonische Vorteil ist real: Aktualisierungen kosten in etwa proportional zu den Änderungen, nicht zur Größe des Komponentenbaums.

    Warum Teams es mögen

    • Kein Konzept der erneuten Darstellung. Die Frage nach dem Grund für eine erneute Darstellung in React tritt nicht auf. useMemo, useCallback und React.memo haben keinen Gegenpart, weil es nichts gibt, was übersprungen werden könnte.
  • Vorhersehbare Effekte. Ein Effekt wird ausgelöst, wenn sich das von ihm gelesene Signal ändert – nicht einfach deshalb, weil ein Komponententeil zufällig neu gerendert wird und die Abhängigkeitsliste dies erlaubt. Veraltete Schließungen, ein bekanntes Problem in React, verschwinden größtenteils, da Werte stets über Getter frisch gelesen werden.
  • Ein sanfter Übergang von React. JSX und die Komponentenkomposition lassen sich fast direkt übernehmen, sodass ein React-Team hauptsächlich nur die problematischen Aspekte wieder loswerden muss, anstatt alles neu zu lernen.
  • Die Gewohnheiten, die man ablegen muss

    Das einmal ausführende Modell hat Folgen, die Anfänger in Verwirrung bringen. Das Auseinandernehmen von Props am Anfang einer Komponente liest deren Werte nur einmal und stört die Reaktivität, weshalb Props in der Regel über props.name aufgerufen werden. Frühzeitige Rückgänge sowie Ternäre im Funktionskörper werden nur einmal ausgewertet, weshalb Solid Kontrollflusskomponenten wie Show und For bereitstellt. Sobald diese Regeln verstanden sind, sind sie konsistent – doch sie stellen die Hauptursache für Fehler bei Entwicklern dar, die aus React kommen.

    Vergleich mit React und Angular

    Der tiefere Unterschied ist eher philosophischer als syntaktischer.

    React hat sein Kernmodell „erneut ausgeführt und verglichen“ und hat jahrelang Tools hinzugefügt, um die Kosten dieses Modells zu senken. Es bleibt weiterhin eine hervorragende Wahl: Sein Ökosystem ist unübertroffen, die Rekrutierung verläuft reibungslos und der React Compiler verringert tatsächlich die manuelle Memoisierung. Der Kompromiss besteht darin, dass man innerhalb eines Modells arbeitet, das an die Beschränkungen seiner Entstehungszeit angepasst ist.

    Angular ist die vollausgestattete Unternehmenslösung mit Dependency Injection, RxJS sowie klaren Konventionen für nahezu alles. Es bewältigt sehr große Codebasen gut, doch die Komplexität und Lernkurve sind erheblich. Seine wichtigsten jüngsten Änderungen, wie Signals und zoneless Change Detection, bringen es in Richtung einer feingranularen Reaktivität, wie sie von Solid popularisiert wurde.

    Diese Entwicklung ist in der gesamten Branche zu beobachten. Angular hat Signals übernommen, React führte einen Compiler zur Kompilierung zu Build-Zeiten ein, neuere Frameworks wie Qwik basieren auf fein abgestimmter Reaktivität, und Vue, dessen reaktive References stets den Signals nahekamen, erforscht mittlerweile eigene Kompilierungsstrategien. Es wäre übertrieben zu behaupten, Svelte und Solid hätten jede dieser Ideen erfunden, doch sie zeigten früh und deutlich, dass Kompilierung und Signals ein ganzes Framework tragen können.

    Warum Entwickler weiterhin in diese Richtung gehen

    Drei weniger spektakuläre Gründe erklären den größten Teil des Interesses:

    • Weniger Frameworks, die man im Kopf behalten muss. Die Aufmerksamkeit richtet sich auf das Produkt statt auf die Update-Semantik des Frameworks. Die korrekte Memoisierung einer Callback-Funktion gilt bei niemandem als sinnvolle Aufgabe.
  • Leistung als Standard.** In React oder Angular wird eine schnelle Anwendung sorgfältig entwickelt. Bei Svelte oder Solid erfordert es in der Regel Anstrengungen, eine Anwendung langsam zu machen.
  • Achtung vor Ihrer Zeit.** Kleinere APIs, weniger Boilerplate und weniger Fallstricke. Entwicklerumfragen haben beide Frameworks wiederholt in Bezug auf Zufriedenheit und Interesse an die Spitze gesetzt, obwohl die Gesamtnutzung auf einer relativ kleinen Basis weiter wächst.
  • Sollten Sie wechseln?

    Für ein bereits existierendes Produkt fast sicher nicht sofort. Wenn eine umfangreiche Anwendung bereits unter React oder Angular läuft und das Team diese Technologien gut kennt, ist eine Neuimplementierung einer der zuverlässigsten Wege, ein Projekt aufzuhalten. Auch die Größe des Ökosystems spielt eine Rolle: React bietet Bibliotheken für nahezu jeden Bedarf, und obwohl die Ökosysteme von Svelte und Solid lebendig sind und wachsen, sind sie kleiner. Prüfen Sie daher frühzeitig, ob die von Ihnen benötigten Komponentenbibliotheken, Formularwerkzeuge sowie Authentifizierungsintegrationen vorhanden sind und gewartet werden.

    Bei neuen Projekten ändert sich die Rechnung. Ein Greenfield-Projekt, ein leistungsintensives Widget oder ein internes Tool sind geeignete Kandidaten mit geringem Risiko, um dies auszuprobieren:

    • wählen Sie Svelte, wenn Sie eine besonders einfache Lernkurve sowie eine Funktionalität wünschen, die im Großen und Ganzen problemlos funktioniert
  • Wählen Sie Solid, wenn Ihr Team in JSX denkt und maximale Laufzeitleistung mit einem auf React basierenden Denkmuster anstrebt.
  • Bleiben Sie bei React oder Angular, wenn die Breite des Ökosystems, die Möglichkeit zur Rekrutierung sowie vorhandenes Fachwissen wichtiger sind als reine Effizienz.
  • Kernpunkte

    • Reacts Render-und-Diff-Modell ist vorhersehbar, doch die Ausführungszeit steigt proportional zum Komponentenbaum; Memoisierung und der React Compiler verringern diese Arbeit, ohne das Modell zu verändern.
    • Svelte 5 bringt die Reaktivität durch Runes wie $state und $derived in den Compiler, wodurch direkte DOM-Änderungen erzeugt und eine kleine Laufzeitbibliothek bereitgestellt wird.
    • Solid führt jede Komponente nur einmal aus und bindet Signale direkt an DOM-Node, wodurch erneute Renderungen vermieden werden – doch dies erfordert neue Gewohnheiten bei Props und Kontrollfluss.
    • Das umfassendere Ökosystem bewegt sich in Richtung derselben Konzepte: Analyse zur Kompilierzeit, Signale anstelle erneuter Darstellungen sowie direkte Aktualisierungen statt Vergleichen.
    • Nehmen Sie diese Frameworks an, wo ihre Stärken relevant sind und das Ökosystem Ihre Anforderungen abdeckt; schreiben Sie keine gesunde Codebasis um, nur um dem Trend zu folgen.