Was ist SolidJS?
SolidJS ist eine deklarative UI-Library, die wie React aussieht, aber grundlegend anders funktioniert. Sie nutzt JSX und Komponenten, verzichtet jedoch komplett auf einen virtuellen DOM und führt keine Re-Renders durch. Stattdessen setzt sie auf fine-grained reactivity: Signals tracken, wer sie liest, und wenn sich ein Wert ändert, werden nur die Berechnungen und DOM-Knoten aktualisiert, die direkt davon abhängen.
In der Praxis bedeutet das, dass eine Solid-Komponentenfunktion genau einmal ausgeführt wird. Alles Reaktive darin wird während dieses Durchlaufs verdrahtet und anschließend punktgenau aktualisiert. Sobald man dieses Konzept verinnerlicht hat, ergeben sowohl die Performance als auch die Regeln von Solid einen Sinn.
Signals
Ein Signal ist ein reaktiver Wert, der mit createSignal erstellt wird. Es gibt einen Getter und einen Setter zurück.
// Counter.jsx
import { createSignal } from "solid-js";
export function Counter() {
const [count, setCount] = createSignal(0);
return (
<button onClick={() => setCount((c) => c + 1)}>
Count: {count()}
</button>
);
}
Sie lesen ein Signal, indem Sie es aufrufen: count(). Dieser Aufruf registriert die Abhängigkeit. Die Übergabe einer Funktion an den Setter (setCount((c) => c + 1)) ist der sichere Weg, um den Wert basierend auf dem vorherigen Zustand zu aktualisieren.
Abgeleitete Werte mit createMemo
createMemo berechnet einen Wert aus anderen Signals und cached diesen. Die Neuberechnung erfolgt nur, wenn sich eine Abhängigkeit ändert, und das Ergebnis wird zwischen allen Lesern geteilt.
// cart.jsx
import { createSignal, createMemo } from "solid-js";
const [items, setItems] = createSignal([{ price: 10 }, { price: 20 }]);
const total = createMemo(() =>
items().reduce((sum, item) => sum + item.price, 0),
);
Für einfache Inline-Ausdrücke können Sie auch eine normale Funktion verwenden, aber createMemo vermeidet die mehrfache Ausführung teurer Operationen. Nutzen Sie es, wenn die Berechnung rechenintensiv ist oder an mehreren Stellen gelesen wird.
Effects
createEffect führt einen Side Effect aus, wann immer sich die gelesenen Signals ändern. Es dient der Synchronisation mit der Außenwelt und nicht der Berechnung von Werten.
// title.jsx
import { createEffect, createSignal } from "solid-js";
const [name, setName] = createSignal("Ada");
createEffect(() => {
document.title = `Hello, ${name()}`;
});
Effects werden nach dem Rendering ausgeführt und tracken ihre Abhängigkeiten automatisch. Verwende onCleanup, um Subscriptions, Timer und Requests aufzuräumen.
Komponenten werden nur einmal ausgeführt
Dies ist die Regel, an der viele React-Entwickler scheitern. Eine Solid-Komponente wird genau einmal ausgeführt. Sie ist eine Setup-Funktion, die reaktive Bindungen erstellt, und keine Funktion, die bei Zustandsänderungen erneut ausgeführt wird.
function Profile(props) {
// Do not destructure props — that breaks reactivity.
// Read them where you use them instead.
return <h1>{props.user.name}</h1>;
}
Da Props reaktive Getter sind, sollten Sie diese dort auslesen, wo Sie sie verwenden (props.user.name), anstatt sie zu destrukturieren. Das Gleiche gilt für Signals: Rufen Sie diese innerhalb des JSX oder innerhalb eines memos auf, nicht einmalig am Anfang der Komponente.
Control-Flow-Komponenten
Solid verwendet anstelle von Template-Direktiven Komponenten für Bedingungen und Listen. Dadurch bleibt alles in JavaScript und der Compiler kann Updates optimieren.
// list.jsx
import { Show, For } from "solid-js";
<Show when={users().length > 0} fallback={<p>No users yet.</p>}>
<ul>
<For each={users()}>{(user) => <li>{user.name}</li>}</For>
</ul>
</Show>
Show rendert seinen Fallback, wenn die Bedingung falsy ist, und For nutzt Referenzen als Keys, sodass DOM-Nodes verschoben werden können, anstatt sie neu zu erstellen. Index steht zur Verfügung, wenn Sie stattdessen den Index als Key verwenden möchten.
Stores
Für verschachtelte reaktive Objekte bietet createStore einen Proxy mit pfadbasierten Updates an.
// store.jsx
import { createStore } from "solid-js/store";
const [user, setUser] = createStore({
name: "Ada",
address: { city: "London" },
});
setUser("address", "city", "Paris");
Nur die Teile des Baums, die sich tatsächlich geändert haben, benachrichtigen ihre Abhängigkeiten. Das bedeutet, dass das Aktualisieren einer tief verschachtelten Eigenschaft keine nicht verwandten Lesezugriffe invalidiert. Stores sind der empfohlene Weg, um strukturierten State zu verwalten.
Ressourcen und asynchrone Daten
createResource kapselt eine asynchrone Funktion in einem Signal und bietet Ihnen Lade- und Fehlerzustände, ohne dass Sie diese manuell verwalten müssen.
// user.jsx
import { createResource, Show } from "solid-js";
const [user] = createResource(() => fetch("/api/user").then((r) => r.json()));
<Show when={user()} fallback={<p>Loading…</p>}>
<h1>{user().name}</h1>
</Show>;
Die Ressource wird erneut ausgeführt, wenn sich ihr Quell-Signal ändert, und bricht veraltete Vorgänge ab. Das macht sie zur idealen Lösung für Daten, die von Routen-Parametern oder Benutzereingaben abhängen.
Routing und SolidStart
Der Solid Router übernimmt die clientseitige Navigation, und SolidStart ist das Meta-Framework, das dateibasiertes Routing, Server Rendering und Data Loading hinzufügt — quasi das Äquivalent zu Next.js für React oder SvelteKit für Svelte. Für alles, was über ein einfaches Widget hinausgeht, solltet ihr mit SolidStart starten.
Best Practices
- Lies Signals und Props dort aus, wo du sie verwendest; destrukturiere sie niemals vorab.
- Nutze
createMemofür rechenintensive oder häufig gemeinsam genutzte abgeleitete Werte. - Nutze
createEffectnur für Side Effects und führe das Cleanup mitonCleanupdurch. - Bevorzuge
createStorefür verschachtelte Zustände. - Nutze
ShowundForanstelle von manuellen Conditionals und.map. - Halte Komponenten als Setup-Funktionen und vermeide es, dich auf eine erneute Ausführung zu verlassen.
- Nutze
createResourcefür asynchrone Daten, die an reaktive Quellen gebunden sind.
Häufige Fehler
- Destrukturierung von Props oder Signal-Werten, wodurch die Reaktivität verloren geht.
- Die Erwartung, dass der Component-Body nach einer Zustandsänderung erneut ausgeführt wird.
- Verwendung eines Effects zur Berechnung eines Wertes anstelle eines Memos.
- Vergessen von
onCleanup, was zu Leaks bei Subscriptions oder Timern führt. - Verwendung von
.mapin JSX anstelle vonFor, wodurch Keyed Updates verloren gehen. - Die Annahme, dass die Regeln von React gelten, und die Suche nach Hooks, die es nicht gibt.
Wie geht es weiter?
Bei Solid zählt das Verständnis mehr als das Auswendiglernen. Vergleiche das Modell mit React, Vue und Svelte, vertiefe deine Kenntnisse in JavaScript und TypeScript und setze für den Build auf Vite. Baue anschließend eine kleine reaktive App und beobachte, wie wenig davon tatsächlich erneut ausgeführt wird.