Was ist Preact?
Preact ist eine winzige Alternative zu React. Es implementiert dasselbe Komponentenmodell, dieselben Hooks und ein virtuelles DOM in etwa drei Kilobyte (gzipped). Für die meisten Komponenten funktioniert der Code, den du für React schreibst, mit wenig oder gar keinen Änderungen auch in Preact.
Genau diese Größe ist der entscheidende Punkt. Wenn du ein Widget in eine Seite einbettest, über die du keine vollständige Kontrolle hast, ein performance-kritisches Interface baust oder einfach dein JavaScript-Budget gering halten möchtest, können ein paar Kilobyte Framework-Größe einen messbaren Unterschied machen. Preact bietet dir das vertraute Modell ohne den unnötigen Ballast.
Komponenten und Hooks
Preact-Komponenten sind Funktionen, die JSX zurückgeben, und Hooks stammen aus preact/hooks.
// Search.jsx
import { useState } from "preact/hooks";
export function Search({ onSearch }) {
const [query, setQuery] = useState("");
return (
<form
onSubmit={(event) => {
event.preventDefault();
onSearch(query);
}}
>
<input
value={query}
onInput={(event) => setQuery(event.currentTarget.value)}
/>
</form>
);
}
useState, useEffect, useRef, useContext, useMemo und useCallback verhalten sich alle so, wie man es erwarten würde. Die Hauptunterschiede sind geringfügig: Preact unterstützt sowohl class als auch className und verwendet native Event-Namen wie onInput und onDblClick.
Preact Signals
Signals sind das primäre Reactivity-Primitive von Preact. Ein Signal hält einen Wert und abonniert bei der Auslesung innerhalb von JSX den entsprechenden Teil des DOMs. Wenn der Wert geändert wird, aktualisiert dies das DOM direkt – ein Re-Render der Komponente ist nicht erforderlich.
// Counter.jsx
import { signal, computed } from "@preact/signals";
const count = signal(0);
const double = computed(() => count.value * 2);
export function Counter() {
return (
<div>
<button onClick={() => count.value++}>
Count: {count}
</button>
<p>Double: {double}</p>
</div>
);
}
Da Signals außerhalb des Komponenten-Baums existieren, können sie von überall aus geteilt und mutiert werden, einschließlich einfacher Module und Event-Handler. Sie sind der empfohlene Weg, um State zu verwalten, der sich häufig ändert.
Die Compat-Layer
Das Paket preact/compat bildet die API von React auf Preact ab. Erstelle in deinem Bundler Aliase für react und react-dom auf dieses Paket, und die meisten React-Bibliotheken funktionieren unverändert.
// vite.config.js
import { defineConfig } from "vite";
import preact from "@preact/preset-vite";
export default defineConfig({
plugins: [preact()],
resolve: {
alias: {
react: "preact/compat",
"react-dom": "preact/compat",
"react-dom/client": "preact/compat/client",
},
},
});
So nutzen Preact-Projekte das React-Ökosystem – Komponenten-Bibliotheken, Routing, State-Manager und mehr – und liefern dennoch eine kleinere Runtime aus. Der Kompromiss ist ein geringer Overhead durch die Compatibility-Layer, die jedoch immer noch weitaus kleiner ist als React selbst.
Kein Build-Schritt mit htm
Wenn Sie den Build-Prozess komplett überspringen möchten, bietet die htm Library eine Alternative zu JSX in Form von Tagged Templates.
// app.js
import { h, render } from "preact";
import htm from "htm";
const html = htm.bind(h);
function App({ name }) {
return html`<h1>Hello, ${name}!</h1>`;
}
render(html`<${App} name="Ada" />`, document.body);
Dies ist besonders praktisch für Progressive Enhancement, schnelle Demos oder das Einbetten einer kleinen interaktiven Island in eine serverseitig gerenderte Seite.
Unterschiede zu React
Die Überschneidungen sind groß, aber einige Details unterscheiden sich:
- Preact verwendet native DOM-Event-Namen, daher ersetzen
onInputundonDblClickeinige React-spezifische Namen. - Sowohl
classals auchclassNamefunktionieren, und sowohlforals auchhtmlForwerden akzeptiert. - Es gibt kein Synthetic Event Pooling, da Preact Events nie gepoolt hat.
- Einige neuere React-Features, wie Teile der Server-Components API, sind nicht implementiert.
- TypeScript JSX-Typen stammen von Preact und müssen bei der Verwendung von compat gealiast werden.
Bei alltäglichen Komponenten und Hooks werden Sie den Unterschied kaum bemerken.
Wann man Preact einsetzen sollte
Preact spielt seine Stärken aus, wenn Größe und Startzeit Priorität haben: einbettbare Widgets, Marketing-Seiten mit geringer Interaktivität, Content-Seiten und Anwendungen mit strikten Performance-Budgets. Es ist zudem ein ideales Ziel für eine sanfte Migration einer bestehenden React-Codebase, die schlanker werden muss.
Wenn Sie auf React-spezifisches Tooling, brandneue Features oder eine Library angewiesen sind, die von React-Internals abhängt, ist es möglicherweise reibungsloser, bei React zu bleiben. Die gute Nachricht ist: Aufgrund der großen API-Überschneidungen ist diese Entscheidung keine Einbahnstraße.
Best Practices
- Verwende Signals für Zustände, die sich häufig ändern oder außerhalb des Trees geteilt werden.
- Greife nur dann auf
preact/compatzurück, wenn du Pakete aus dem React-Ökosystem benötigst. - Erstelle Aliase für React-Typen sowie Runtime-Module, wenn du
compatverwendest. - Halte Komponenten klein und vermeide unnötige Re-renders, indem du Signals direkt an der Stelle liest, an der sie benötigt werden.
- Miss die tatsächlichen Auswirkungen auf das Bundle – die Einsparungen sind signifikant, aber dein eigener Code bleibt der dominierende Faktor.
- Bevorzuge
preact/preset-vite, um den Build direkt ab Werk korrekt zu konfigurieren.
Häufige Fehler
- Mischen von React- und Preact-Paketen ohne den
compat-Alias. - Vergessen,
react-dom/clientzu aliasieren, was die neue Root-API beeinträchtigt. - Die Annahme, dass jede React-Library ohne Testen der Compat-Layer funktioniert.
- Übermäßiger Einsatz von Signals und das Re-Rendering von Komponenten, die ein Signal direkt lesen könnten.
- Preact als feature-identisch zu React zu betrachten und dann von einem Edge-Case überrascht zu werden.
- Preact zur Reduzierung der Bundle-Größe einzusetzen, nur um dann eine große Dependency hinzuzufügen, die den Gewinn wieder zunichtemacht.
Wie geht es weiter?
Preact ist die pragmatische Antwort, wenn das Modell von React zwar überzeugt, die Größe jedoch zu hoch ist. Vergleiche es mit React und Svelte, verbinde es mit Vite und behalte deine JavaScript-Grundlagen im Blick. Versuche anschließend, ein kleines Preact-Widget in eine einfache HTML-Seite einzubetten, um zu sehen, wie gering der Overhead ist.