Back

Best Practices für die Arbeit mit SolidJS

Best Practices für die Arbeit mit SolidJS

SolidJS liefert nahezu native DOM-Performance durch feinkörnige Reaktivität, aber genau dieses Modell führt zu Mustern, die Entwickler stolpern lassen, die von React oder Vue kommen. Dieser Artikel behandelt die SolidJS Best Practices, die in echten Anwendungen am wichtigsten sind — diejenigen, die subtile Bugs verhindern und Ihren Code vorhersagbar halten.

Wichtigste Erkenntnisse

  • SolidJS-Komponenten werden einmal als Setup-Funktionen ausgeführt — Reaktivität findet auf Signal-Ebene statt, nicht auf Komponenten-Ebene
  • Halten Sie Signal-Lesevorgänge innerhalb reaktiver Bereiche: JSX-Ausdrücke, createEffect oder createMemo
  • Leiten Sie Werte mit Funktionen oder createMemo ab, anstatt State durch Effects zu synchronisieren
  • Destrukturieren Sie niemals Props — verwenden Sie mergeProps und splitProps, um die Getter-Kette zu erhalten
  • Verwenden Sie createStore für verschachtelten State und createResource für asynchrones Datenabrufen

Verstehen Sie, dass Komponenten einmal ausgeführt werden

Dies ist die mentale Modellverschiebung, von der alles andere abhängt. In React rendern Komponenten neu, wenn sich der State ändert. In SolidJS werden Komponenten einmal als Setup-Funktionen ausgeführt. Reaktivität findet auf Signal-Ebene statt, nicht auf Komponenten-Ebene.

Das bedeutet, dass dies fehlerhaft ist:

function Counter() {
  const [count, setCount] = createSignal(0)
  const doubled = count() * 2 // Wird einmal ausgeführt. Aktualisiert nie.
  return <div>{doubled}</div>
}

Die Lösung besteht darin, Signal-Lesevorgänge innerhalb reaktiver Bereiche zu halten — JSX-Ausdrücke, createEffect oder createMemo:

function Counter() {
  const [count, setCount] = createSignal(0)
  const doubled = createMemo(() => count() * 2) // Verfolgt count reaktiv
  return <div>{doubled()}</div>
}

SolidJS-Reaktivitätsmuster: Signals, Memos und Effects

Feinkörnige Reaktivität in SolidJS basiert auf drei Primitiven. Zu wissen, wann man welches verwendet, ist zentral für das Schreiben effizienter SolidJS-Komponenten.

  • createSignal — für primitive Werte und einfachen State
  • createMemo — für abgeleitete Werte, die von Signals abhängen
  • createEffect — nur für Seiteneffekte (DOM-Manipulation, Drittanbieter-Bibliotheken)

Der häufigste Fehler ist die Verwendung von createEffect zur Synchronisierung von State:

// ❌ Anti-Pattern: Effect für Ableitung verwendet
createEffect(() => setFullName(`${firstName()} ${lastName()}`))

// ✅ Korrekt: direkt ableiten
const fullName = () => `${firstName()} ${lastName()}`

Eine einfache Funktion wie fullName funktioniert, weil SolidJS sie neu auswertet, wann immer sie innerhalb eines reaktiven Bereichs erscheint, der ihre zugrunde liegenden Signals liest. Greifen Sie nur dann zu createMemo, wenn die Ableitung teuer ist und Sie das Ergebnis cachen möchten.

Reservieren Sie createEffect für Arbeiten außerhalb des reaktiven Graphen von Solid — Dinge wie die Initialisierung einer Chart-Bibliothek oder die imperative Aktualisierung eines DOM-Elements. Siehe die offizielle Erklärung zu Memos und abgeleiteten Werten für tiefere Details.

Destrukturieren Sie niemals Props

SolidJS-Props basieren auf Gettern. Ihre Destrukturierung unterbricht die reaktive Verbindung:

// ❌ Unterbricht Reaktivität
function User({ name }: { name: string }) {
  return <h1>{name}</h1>
}

// ✅ Erhält Reaktivität
function User(props: { name: string }) {
  return <h1>{props.name}</h1>
}

Wenn Sie Standardwerte benötigen oder Props, die Sie konsumieren, von Props trennen möchten, die Sie weiterleiten, verwenden Sie mergeProps und splitProps — beide erhalten die Getter-Kette.

Verwenden Sie Control-Flow-Komponenten für bedingte und Listen-Rendering

SolidJS-Performance-Muster hängen davon ab, die richtigen Rendering-Primitive zu verwenden. Bevorzugen Sie Solids Control-Flow-Komponenten für reaktive Bedingungen und Listen, anstatt sich auf rohe JavaScript-Logik innerhalb von JSX zu verlassen.

// ✅ Bedingtes Rendering
<Show when={isLoggedIn()} fallback={<LoginPage />}>
  <Dashboard />
</Show>

// ✅ Listen-Rendering — erhält Item-Identität über Updates hinweg
<For each={posts()}>{(post) => <PostCard post={post} />}</For>

Verwenden Sie <Index> anstelle von <For>, wenn Listenpositionen stabil bleiben, aber Werte an diesen Positionen sich ändern können. <For> verfolgt Items nach Referenz und funktioniert am besten für Arrays von Objekten mit stabiler Identität, während <Index> Items nach Position verfolgt.

Sie können mehr über Solids Listen-Rendering-Primitive in der offiziellen Dokumentation lesen.

Verwenden Sie Stores für komplexen State

Signals verfolgen Änderungen an einem einzelnen Wert. Wenn dieser Wert ein großes verschachteltes Objekt ist, ersetzen Updates den gesamten Wert, was bedeutet, dass alle Konsumenten dieses Signals auf die Änderung reagieren. createStore bietet Reaktivität auf Eigenschaftsebene, die besser für verschachtelten State funktioniert:

const [state, setState] = createStore({ user: { name: "Alice" }, posts: [] })

// Nur Komponenten, die state.posts lesen, reagieren darauf
setState("posts", (p) => [...p, newPost])

Verwenden Sie produce für komplexe Mutationen und reconcile beim Zusammenführen von Serverdaten in einen bestehenden Store.

Asynchrone Daten richtig handhaben

Das Abrufen innerhalb von createEffect kann zu Race Conditions führen und integriert sich nicht sauber mit Suspense. Verwenden Sie stattdessen createResource:

const [posts] = createResource(() => fetch("/api/posts").then((r) => r.json()))

createResource akzeptiert ein optionales Quell-Signal als erstes Argument. Wenn es bereitgestellt wird, wird der Fetcher erneut ausgeführt, wann immer sich diese Quelle ändert, und die Ressource integriert sich automatisch mit Solids <Suspense>- und <ErrorBoundary>-Komponenten.

In SolidStart-Apps verwenden Sie query und createAsync zusammen mit Preload-Funktionen. Preload-Funktionen können während der Navigationsabsicht (z. B. Link-Hover) und erneut während der Navigation ausgeführt werden, sodass Daten bereit sein können, wenn die Komponente rendert.

Fazit

SolidJS belohnt Entwickler, die mit seinem Reaktivitätsmodell arbeiten, anstatt dagegen. Halten Sie Signal-Lesevorgänge innerhalb reaktiver Bereiche, leiten Sie Werte ab, anstatt sie mit Effects zu synchronisieren, destrukturieren Sie niemals Props und greifen Sie zu createStore, wenn State eine verschachtelte Struktur hat. Diese SolidJS-Reaktivitätsmuster sind keine willkürlichen Regeln — sie sind die direkte Konsequenz davon, wie feinkörnige Reaktivität funktioniert, und ihre Befolgung produziert Komponenten, die sowohl korrekt als auch schnell sind.

FAQs

SolidJS-Komponenten werden einmal ausgeführt, sodass jeder Signal-Lesevorgang, der einer einfachen Variablen außerhalb eines reaktiven Bereichs zugewiesen wird, nur den Anfangswert erfasst. Wickeln Sie die Ableitung in createMemo ein oder platzieren Sie den Signal-Lesevorgang direkt innerhalb von JSX. Beide sind reaktive Bereiche, die sich neu auswerten, wann immer sich das zugrunde liegende Signal ändert.

Eine einfache abgeleitete Funktion funktioniert gut für leichtgewichtige Berechnungen, da SolidJS sie jedes Mal neu auswertet, wenn ein konsumierender reaktiver Bereich ausgeführt wird. Verwenden Sie createMemo, wenn die Ableitung teuer ist oder von mehreren Konsumenten gelesen wird. createMemo cached das Ergebnis und berechnet nur neu, wenn sich seine Abhängigkeiten ändern.

For verfolgt jedes Item nach Referenz, daher ist es ideal für Arrays von Objekten mit stabiler Identität. Index verfolgt Items nach ihrer Position im Array, was es besser für Listen geeignet macht, bei denen die Position stabil bleibt, aber der Wert an dieser Position sich ändern kann.

Sie können, aber Sie sollten nicht. Die Verwendung von createEffect zur Synchronisierung abgeleiteten States erzeugt unnötige Zwischenaktualisierungen und kann Glitches einführen. Leiten Sie stattdessen den Wert mit einer Funktion oder createMemo ab. Reservieren Sie createEffect für echte Seiteneffekte wie DOM-Manipulation, Logging oder Interaktion mit Drittanbieter-Bibliotheken.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay