Vue 3: Composition API oder Options API, wofür jede wirklich gedacht ist

  • vuetelemetry
  • Leitfäden
  • 6 Min. Lesezeit

Die Composition API ersetzt die Options API nicht. Beide lösen unterschiedliche Probleme in unterschiedlicher Größenordnung, und die Entscheidung hängt weniger davon ab, welche neuer ist, als davon, wie Ihre Komponente wächst. Was jede leistet, wo jede an Grenzen stößt und wie Sie wählen, ohne funktionierenden Code neu zu schreiben.

Vue 3 bringt beide APIs mit. Die Options API ist das, was Vue schon immer hatte: Eine Komponente ist ein Objekt mit `data`, `computed`, `methods`, `watch` und Lifecycle-Hooks als benannten Eigenschaften. Die mit Vue 3 eingeführte Composition API erlaubt es, dieselbe Logik als gewöhnliche Funktionen in einer `setup()`-Funktion oder einem `<script setup>`-Block zu schreiben. Keine von beiden ist veraltet, und keine wird verschwinden.

Die Options API ordnet Code nach Optionstyp. Der gesamte reaktive Zustand gehört in `data()`. Alle berechneten Werte gehören in `computed`. Alle Methoden gehören in `methods`. Bei kleinen Komponenten ist das übersichtlich, weil jedes Thema nur wenige Zeilen pro Abschnitt umfasst und man die Abschnitte schnell überblickt. Zum Problem wird es, wenn eine Komponente wächst: Eine einzelne Funktion (etwa ein Suchfilter) hat ihren Zustand in `data`, ihre abgeleiteten Werte in `computed`, ihre Event-Handler in `methods` und ihre Initialisierung in `mounted`. Sie ist über vier Stellen der Datei verteilt.

Wie die Options API Code organisiert

Kupferleiterbahnen auf einer schwarzen Leiterplatte, die von einem achteckigen Pad in der Mitte in alle Richtungen verlaufen, umgeben von kleinen SMD-Bauteilen mit den Bezeichnungen S4 bis S12.
Kupferleiterbahnen auf einer schwarzen Leiterplatte, die von einem achteckigen Pad in der Mitte in alle Richtungen verlaufen, umgeben von kleinen SMD-Bauteilen mit den Bezeichnungen S4 bis S12.

Die Composition API ordnet Code nach logischem Belang. Statt den gesamten Zustand an einer Stelle und alle Methoden an einer anderen abzulegen, fasst man Zustand, berechnete Werte, Watcher und Funktionen zusammen, die zu einer Funktion gehören. Ein Suchfilter wird zu einem Block von 15 Zeilen, der alles enthält, was er braucht. Die Paginierung wird zu einem weiteren Block. Sie stehen in der Datei nebeneinander, und man kann einen lesen, ohne in drei andere Abschnitte zu springen.

Das zählt nur bei großen Komponenten. Eine Komponente mit einem Zustand, einem berechneten Wert und einer Methode ist in beiden APIs gleich gut lesbar. Die Composition API zahlt sich aus, sobald eine Komponente drei oder mehr unabhängige Belange hat, denn ab dann zwingt die Options API dazu, unzusammenhängende Logik über die Abschnitte zu verschränken.

Wie die Composition API Code organisiert

`<script setup>` ist die Syntax, die der meiste neue Vue-3-Code verwendet. Sie ist eine Kurzform zur Kompilierzeit, die eine explizite `setup()`-Funktion samt return-Anweisung überflüssig macht. Auf oberster Ebene deklarierte Variablen stehen im Template automatisch zur Verfügung. Props werden mit `defineProps()` deklariert, Events mit `defineEmits()`. Beides sind Compiler-Makros, die nicht importiert werden müssen.

  • Die Options API ordnet Code nach Typ (data, computed, methods), die Composition API nach Funktion
  • Keine der beiden APIs ist veraltet, und beide nutzen dasselbe Reaktivitätssystem
  • ref() ist gegenüber reactive() die empfohlene Voreinstellung, um Fehler bei Neuzuweisung und Destrukturierung zu vermeiden
  • Composables ersetzen Mixins für komponentenübergreifend wiederverwendbare Logik ohne Namenskollisionen
  • Die TypeScript-Inferenz funktioniert mit der Composition API natürlich und hat mit dem this der Options API Mühe
  • Eine Migration ist optional: Beide APIs bestehen im selben Projekt und sogar in derselben Komponente nebeneinander

Reaktivität in der Composition API beruht auf `ref()` und `reactive()`. `ref()` umhüllt einen einzelnen Wert und verlangt `.value`, um ihn in JavaScript zu lesen oder zu schreiben (nicht aber im Template, wo Vue ihn automatisch auspackt). `reactive()` umhüllt ein Objekt, dessen Eigenschaften ohne `.value` reaktiv sind. Die häufigste Fehlerquelle ist ein vergessenes `.value` im Script oder ein überflüssiges im Template.

ref, reactive und script setup

`ref()` ist fast immer die richtige Voreinstellung. `reactive()` hat zwei Einschränkungen, über die viele stolpern. Erstens kann man das ganze Objekt nicht neu zuweisen (der Proxy hängt an der ursprünglichen Referenz, nicht an der Variablen). Zweitens verlieren die Eigenschaften beim Destrukturieren eines reaktiven Objekts ihre Reaktivität. `ref()` hat keines der beiden Probleme, und der Aufwand für `.value` ist gering im Vergleich zu den Kosten, solche Randfälle zu debuggen.

Composables sind der wichtigste strukturelle Vorteil. Ein Composable ist eine Funktion, die Primitive der Composition API (`ref`, `computed`, `watch`, `onMounted`) nutzt und reaktiven Zustand zurückgibt. `useMouse()`, `useFetch()` und `useLocalStorage()` sind typische Beispiele. Man ruft sie in `setup()` auf und erhält reaktive Werte zurück. Genau dieses Muster kann die Options API nicht sauber nachbilden: Mixins teilen Logik zwischen Komponenten, verschmelzen Eigenschaften aber nach Namen, was stille Kollisionen erzeugt und unklar macht, woher eine Eigenschaft stammt.

Mixins sind das Gegenstück der Options API, und sie werden im großen Maßstab problematisch. Definieren zwei Mixins eine `data`-Eigenschaft mit demselben Namen, gewinnt eine davon stillschweigend. Fügt ein Mixin eine Methode hinzu, hat die Komponente dafür keine sichtbare Deklaration. Je mehr Mixins hinzukommen, desto unklarer wird die Herkunft einer Eigenschaft. Die Vue-Dokumentation empfiehlt ausdrücklich Composables statt Mixins für wiederverwendbare Logik in Vue 3.

Composables versus Mixins

Die TypeScript-Unterstützung ist in der Composition API deutlich besser. Die Options API braucht den Wrapper `defineComponent()`, und die Typinferenz läuft über einen komplexen `this`-Typ, der mit bestimmten Mustern Mühe hat (verschachtelte Callbacks, externe Funktionen, die auf den Komponentenzustand zugreifen). Die Composition API verwendet gewöhnliche Variablen mit Standard-TypeScript-Typen. `ref<number>(0)` liefert ein `Ref<number>`. Composables haben typisierte Rückgabewerte. Die IDE-Unterstützung (Autovervollständigung, Typen beim Überfahren, Refactoring) funktioniert wie bei jeder TypeScript-Funktion.

Die Laufzeitleistung ist ähnlich, mit zwei dokumentierten Vorteilen für die Composition API. Das Reaktivitätssystem ist in beiden Fällen dasselbe. Laut Vue-Dokumentation lässt sich Code in `<script setup>` besser minifizieren, weil das Template zu einer Funktion im selben Gültigkeitsbereich kompiliert wird und lokale Variablennamen gekürzt werden können, während Options-API-Code über Eigenschaftszugriffe auf `this` läuft. Ein Projekt, das nur die Composition API nutzt, kann die Options API außerdem mit dem Kompilier-Flag `__VUE_OPTIONS_API__` abschalten, wodurch sie aus dem Produktions-Bundle entfällt. Für die meisten Anwendungen sind diese Gewinne klein im Vergleich zur Organisation des Codes.

**Die Laufzeitleistung ist ähnlich, mit zwei dokumentierten Vorteilen für die Composition API.** Das Reaktivitätssystem ist in beiden Fällen dasselbe. Laut Vue-Dokumentation lässt sich Code in `<script setup>` besser minifizieren, weil das Template zu einer Funktion im selben Gültigkeitsbereich kompiliert wird und lokale Variablennamen gekürzt werden können, während Options-API-Code über Eigenschaftszugriffe auf `this` läuft. Ein Projekt, das nur die Composition API nutzt, kann die Options API außerdem mit dem Kompilier-Flag `__VUE_OPTIONS_API__` abschalten, wodurch sie aus dem Produktions-Bundle entfällt. Für die meisten Anwendungen sind diese Gewinne klein im Vergleich zur Organisation des Codes.

- vuetelemetry

TypeScript, Performance und Migration

Eine Migration ist nicht nötig. Vue 3 unterstützt beide APIs im selben Projekt und bei Bedarf in derselben Datei. Eine Options-API-Komponente kann ein Composable nutzen, indem sie es in einer `setup()`-Methode neben den bestehenden Optionen aufruft. Funktionierende Options-API-Komponenten müssen nicht neu geschrieben werden. Der praktische Weg: neue Komponenten mit `<script setup>` schreiben und alte nur dann umbauen, wenn man sie ohnehin aus anderen Gründen bearbeitet.

Wann die Options API passt. Kleine bis mittlere Komponenten mit überschaubarer Logik. Teams, in denen die meisten Entwickler Vue gerade lernen und von einer expliziten Struktur profitieren. Codebasen mit bestehendem Options-API-Code, der kein Refactoring braucht. Schnelles Prototyping, bei dem das Benennen von Refs und Composables mehr bremst, als die bessere Organisation hilft.

Wann die Composition API passt. Komponenten mit mehreren unabhängigen Belangen. Jede Situation, in der zustandsbehaftete Logik zwischen Komponenten geteilt werden muss (Composables ersetzen Mixins). Projekte mit TypeScript. Bibliotheken und Open-Source-Pakete (Composables sind das erwartete Verteilungsformat). Große Anwendungen, deren Komponentendateien regelmäßig mehr als 200 Zeilen haben.

FAQ

Ist die Options API in Vue 3 veraltet?

Nein. Das Vue-Team pflegt beide APIs gleichrangig. Die Options API ist nicht veraltet, ihre Entfernung ist nicht geplant, und sie erhält dieselben Updates. Die Dokumentation stellt beide nebeneinander dar. Die Wahl der Composition API ist eine Entscheidung über die Organisation des Codes, nicht darüber, auf dem neuesten Stand zu bleiben.

Sollte ich meine Options-API-Komponenten auf die Composition API umschreiben?

Nur wenn es einen Grund jenseits der API selbst gibt. Funktionierender Options-API-Code wird nicht schlechter, weil es die Composition API gibt. Praktisch ist es, neue Komponenten mit der Composition API zu schreiben und alte nur dann umzubauen, wenn man sie ohnehin ändert und das Refactoring die Änderung erleichtert.

Was ist der Unterschied zwischen ref und reactive in Vue 3?

ref() umhüllt einen einzelnen Wert und verlangt .value, um im Script darauf zuzugreifen. reactive() umhüllt ein Objekt, dessen Eigenschaften ohne .value reaktiv sind. Der wichtigste praktische Unterschied: reactive() verliert seine Reaktivität beim Destrukturieren oder wenn das ganze Objekt neu zugewiesen wird, ref() hat keines der beiden Probleme. Die Vue-Dokumentation und die meisten Community-Leitfäden empfehlen ref() als Voreinstellung.

Verwandter Stack