Zum Inhalt springen
Alle Artikel

React vs. Vue vs. Svelte: Welches Frontend passt zum Projekt?

Dieselbe Suche in drei Umsetzungen. Wir vergleichen Datenfluss, Fehlerbehandlung und die Fragen, die bei Auswahl, Wartung und Übergabe an eine Agentur zählen.

Praxisvergleich

React, Vue und Svelte im Projektvergleich

Eine Suche. Drei Umsetzungen.

Dieselbe Suche in React, Vue und Svelte. Wechseln Sie zwischen den Codebeispielen und vergleichen Sie Zustände, Eingabebindung und die Ausgabe der Ergebnisse.

Umsetzung vergleichenGleiche Aufgabe, andere Werkzeuge
So funktioniert es

useState hält Eingabe und Ergebnis. useEffect startet die Suche; seine Aufräumfunktion beendet Timer und überholte Anfragen.

Wann wir es wählen

Passt, wenn bereits React-Komponenten vorhanden sind oder die Agentur ein React-Projekt weiterführen möchte.

Was wir dabei abwägen

Effekt-Abhängigkeiten und asynchrone Zustände brauchen klare Regeln. Für größere Anwendungen legen wir Datenabrufe und Fehlerbehandlung gemeinsam fest.

Code in React
TopicSearch.tsx
'use client'
import { useEffect, useState } from 'react'
import { searchTopics, type Topic } from './search-source'

export function TopicSearch() {
  const [query, setQuery] = useState('')
  const [items, setItems] = useState<Topic[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState('')

  useEffect(() => {
    const controller = new AbortController()
    setLoading(true)
    setError('')
    const timer = setTimeout(async () => {
      try {
        const results = await searchTopics(query, { signal: controller.signal })
        if (!controller.signal.aborted) setItems(results)
      } catch {
        if (!controller.signal.aborted) setError('Die Suche ist nicht erreichbar.')
      } finally {
        if (!controller.signal.aborted) setLoading(false)
      }
    }, 250)
    return () => { clearTimeout(timer); controller.abort() }
  }, [query])

  return <section>
    <label>Thema suchen
      <input value={query} onChange={event => setQuery(event.target.value)} />
    </label>
    <div role="status" aria-live="polite" aria-busy={loading}>
      {loading ? <p>Suche läuft …</p> : error ? <p>{error}</p> :
        items.length === 0 ? <p>Keine passenden Themen.</p> :
        <ul>{items.map(item => <li key={item.id}>{item.title}</li>)}</ul>}
    </div>
  </section>
}
Rahmen des Beispiels und gemeinsame Datenquelle

Alle drei Beispiele verwenden dieselbe lokale Datenquelle search-source.ts. Nach einer kurzen Eingabepause startet die Suche. Eine neue Eingabe bricht die vorherige Anfrage ab. Ladezustand, leere Ergebnisse und Fehler gehören zur gleichen Aufgabe. Die gemeinsame Hilfsdatei steht unten; die Codeansicht oben zeigt die jeweilige Komponente.

search-source.ts
export interface Topic {
  id: string
  title: string
  category: string
}

const topics: Topic[] = [
  { id: 'design', title: 'Designsystem aufbauen', category: 'Gestaltung' },
  { id: 'cms', title: 'Inhalte mit einem CMS pflegen', category: 'Websites' },
  { id: 'api', title: 'Schnittstellen verbinden', category: 'Entwicklung' },
  {
    id: 'forms',
    title: 'Formulare verständlich gestalten',
    category: 'Gestaltung',
  },
]

// Lokale Beispieldaten. Die Verzögerung macht Ladezustände sichtbar;
// sie misst nicht die Geschwindigkeit eines Frameworks.
export function searchTopics(
  query: string,
  { signal, fail = false }: { signal: AbortSignal; fail?: boolean },
): Promise<Topic[]> {
  return new Promise((resolve, reject) => {
    if (signal.aborted) {
      reject(new DOMException('Suche abgebrochen', 'AbortError'))
      return
    }
    const cancel = () => {
      clearTimeout(timer)
      reject(new DOMException('Suche abgebrochen', 'AbortError'))
    }
    const timer = setTimeout(() => {
      signal.removeEventListener('abort', cancel)
      if (fail) {
        reject(new Error('Die Suche ist gerade nicht erreichbar.'))
        return
      }
      const term = query.trim().toLocaleLowerCase('de')
      resolve(
        topics.filter((topic) =>
          `${topic.title} ${topic.category}`
            .toLocaleLowerCase('de')
            .includes(term),
        ),
      )
    }, 400)
    signal.addEventListener('abort', cancel, { once: true })
  })
}

React, Vue und Svelte können dieselbe interaktive Oberfläche bauen. Eine Suche, ein Formular oder ein Kundenportal legt deshalb noch kein bestimmtes Werkzeug fest. Für die Auswahl müssen wir wissen, was bereits vorhanden ist, welche Integrationen gebraucht werden und wer die Anwendung nach der Übergabe betreut. Das gemeinsame Beispiel oben macht einen Teil dieser Arbeit sichtbar: den Umgang mit Eingaben und asynchronen Ergebnissen.

Was der gemeinsame Suchvergleich zeigt

Alle drei Implementierungen verwenden dieselbe Datenquelle und dieselben Themen. Nach einer kurzen Eingabepause startet eine Anfrage. Ändert sich der Suchbegriff erneut, wird die vorherige Anfrage abgebrochen. Die Oberfläche unterscheidet zwischen laufender Suche, passenden Treffern, einer leeren Liste und einem Fehler. So vergleichen wir die Umsetzung derselben Aufgabe statt unterschiedlich umfangreiche Beispiele.

Die Codeansichten stellen dieselbe Kernlogik gegenüber. Bei React stehen Zustände und Darstellung in einer Funktion mit JSX. Vue und Svelte verwenden jeweils einen Script-Bereich und ein Template. So lassen sich Eingabebindung, bedingte Ausgabe und das Aufräumen einer laufenden Anfrage direkt vergleichen. Die gemeinsame Hilfsdatei steht unter den Beispielen. Eine vollständige Anwendung kann für Datenabrufe zusätzliche Bibliotheken oder die Möglichkeiten ihres Anwendungsframeworks nutzen.

React: Zustände und Effekte ausdrücklich verbinden

Im React-Beispiel hält useState den Suchbegriff, die Treffer und die Rückmeldungen. useEffect reagiert auf eine geänderte Eingabe. Seine Aufräumfunktion beendet den Timer und bricht die alte Anfrage ab. Vor einer Zustandsänderung prüfen wir zusätzlich das Abbruchsignal. Damit kann ein überholter Abruf seine Ergebnisse nicht nachträglich in die aktuelle Suche schreiben.

Für ein Projekt ist diese Arbeitsweise vor allem dann naheliegend, wenn bereits React-Komponenten, Integrationen oder entsprechende Kenntnisse vorhanden sind. Wir prüfen, wie gemeinsam genutzte Zustände und Datenabrufe organisiert werden sollen. Das kleine Beispiel entscheidet weder über eine zusätzliche Zustandsbibliothek noch über die Architektur einer ganzen Anwendung. Diese Entscheidungen brauchen den tatsächlichen Umfang und die Verantwortlichkeiten im Team.

Vue: Daten beobachten und im Template darstellen

Vue trennt im Beispiel den Script-Bereich von der Darstellung im Template. ref hält veränderliche Werte, watch beobachtet den Suchbegriff. Die übergebene onCleanup-Funktion beendet den vorherigen Timer und Abruf. v-model verbindet das Eingabefeld mit dem Suchbegriff; die bedingten Template-Blöcke zeigen den jeweiligen Zustand. Damit wird dieselbe Aufgabe über die Reaktivitäts- und Template-Mittel von Vue beschrieben.

Vue ist für uns eine naheliegende Option, wenn eine Agentur bereits damit arbeitet oder vorhandene Vue-Oberflächen erweitert werden sollen. Vor einer Entscheidung schauen wir uns die benötigten Komponenten und deren Schnittstellen an. Auch ein übersichtliches Template braucht verständliche Zuständigkeiten: Was gehört in die Komponente, was in wiederverwendbare Logik und was auf den Server? Diese Aufteilung trägt mehr zur späteren Wartung bei als die reine Länge des Beispiels.

Svelte: Reaktivität mit Compiler-Unterstützung

Svelte übersetzt Komponenten mit einem Compiler. Im Beispiel halten $state-Werte die Eingabe und das Ergebnis. $effect liest den Suchbegriff synchron, bevor der verzögerte Abruf beginnt. Das ist relevant, weil synchron gelesene reaktive Werte als Abhängigkeiten erfasst werden. Die zurückgegebene Aufräumfunktion beendet Timer und Anfrage. Ein Compiler nimmt der Anwendung die Verantwortung für Fehler- und Ladezustände also nicht ab.

Wir ziehen Svelte für eigenständige Oberflächen und interaktive Werkzeuge in Betracht, wenn die erforderlichen Integrationen passen und das spätere Betreuungsteam damit arbeiten kann. Vor der Festlegung prüfen wir insbesondere die tatsächlich benötigten Komponenten. Eine mögliche zusätzliche Integration gehört in die Planung. Aus einem kürzeren Beispiel lässt sich weder eine kürzere Projektlaufzeit noch eine höhere Geschwindigkeit der fertigen Anwendung ableiten.

Welche Fragen die Auswahl wirklich entscheiden

Diese Fragen klären wir vor der Festlegung:

  • Bestand: Welche Komponenten, Designsysteme und Schnittstellen sollen weiterverwendet werden?
  • Interaktion: Welche Zustände, Formulare, Berechtigungen und längeren Abläufe muss die Oberfläche abbilden?
  • Integration: Sind die benötigten Tabellen, Editoren, Karten oder anderen Komponenten verfügbar und für den vorgesehenen Einsatz geeignet?
  • Übernahme: Wer pflegt das Projekt später und mit welchen Werkzeugen arbeitet dieses Team bereits?
  • Betrieb: Welche Teile benötigen serverseitige Daten, welche können statisch ausgeliefert werden und wie werden Fehler nachvollzogen?

Bei einer vorhandenen, tragfähigen Codebasis prüfen wir zuerst deren Weiterentwicklung. Ein Wechsel muss einen konkreten Nutzen haben, der Migration und Einarbeitung rechtfertigt. Bei einem neuen Projekt kann eine kleine Umsetzung des schwierigsten Ablaufs helfen, offene Integrationsfragen vor der endgültigen Festlegung zu klären. Eine einfache Suchliste wäre dafür zu wenig, wenn das spätere Projekt vor allem an einem komplexen Editor oder einer speziellen Schnittstelle hängt.

Was ein Codevergleich nicht entscheiden kann

Zeilenzahl, Dateianzahl und die Schreibweise eines Templates zeigen Unterschiede im Ausdruck, aber keine allgemeine Rangfolge. Für Aussagen zur Performance brauchen wir dieselbe vollständige Aufgabe, vergleichbare Daten, dasselbe Gerät und nachvollziehbare Messbedingungen. Bilder, Drittanbieter-Scripts und Datenabrufe können das Ergebnis stärker beeinflussen als der sichtbare Komponentenquelltext. Hier veröffentlichen wir deshalb keine aus dem Beispiel abgeleiteten Geschwindigkeitswerte.

Für einen Agenturkunden wird der Vergleich nützlich, wenn er die Folgen einer Wahl erklärt. Dazu gehören Erweiterbarkeit, Übergabe und die Anforderungen an das spätere Team. Unsere Einordnung benennt deshalb passende Situationen und Abwägungen. Es gibt keinen pauschalen Gewinner, den wir unabhängig vom Projekt empfehlen.

Wann Next.js, Nuxt oder SvelteKit dazukommen

Sobald Routing, serverseitiges Laden von Inhalten und das Zusammenspiel von Seite und Server Teil der Entscheidung sind, reicht der Blick auf eine UI-Komponente nicht mehr aus. Dann vergleichen wir zusätzlich Next.js im React-Umfeld, Nuxt im Vue-Umfeld und SvelteKit im Svelte-Umfeld. Dafür verwenden wir ein eigenes gemeinsames Beispiel: einen veröffentlichten Artikel aus einem CMS laden und auf der Seite ausgeben. Die Ebenen bleiben getrennt, damit aus einer Vorliebe für eine Template-Syntax keine unbegründete Architekturentscheidung wird.

Quellen zum Vergleich

Technische Grundlagen und weiterführende Dokumentation, geprüft am 9. September 2026. Die Empfehlungen zur Projektwahl sind unsere Einordnung.

Passende Technologien

Und Ihr Projekt?

Sprechen Sie mit uns über die technischen und organisatorischen Fragen, die Sie gerade beschäftigen.

Kontakt aufnehmen