Lebenszyklus und Datenabfragen

In diesem Kapitel lernst du die Lifecycle-Hooks von Vue3 kennen und verwendest fetch, um Blog-Daten zum richtigen Zeitpunkt aus einer JSON-Datei zu laden.


Was ist ein Lebenszyklus?

Jede Vue-Komponente durchläuft eine Reihe von Phasen von der Erstellung bis zur Zerstörung; diese Phasen werden als "Lebenszyklus" bezeichnet.

Vue stellt in jeder Phase entsprechendeHook-Funktionenbereit, mit denen du Code zu bestimmten Zeitpunkten ausführen kannst.

Wenn du zum Beispiel Daten anfordern möchtest, nachdem die Komponente fertig geladen ist, musst duonMounteddiesen Hook verwenden.


Überblick über Vue3 Lifecycle-Hooks

Hook-FunktionAusführungszeitpunktHäufige Anwendungsfälle
setup()Komponenteninitialisierung, wird am frühesten ausgeführtReaktive Daten und berechnete Eigenschaften definieren
onBeforeMountBevor die Komponente in das DOM eingebunden wirdWeniger häufig verwendet
onMountedNachdem die Komponente in das DOM eingebunden wurdeNetzwerkanfragen stellen, Bibliotheken von Drittanbietern initialisieren, DOM-Referenzen abrufen
onBeforeUpdateBevor sich Daten ändern und das DOM aktualisiert wirdWeniger häufig verwendet
onUpdatedNach Datenänderungen und DOM-AktualisierungenOperationen nach DOM-Aktualisierungen
onBeforeUnmountBevor die Komponente zerstört wirdTimer löschen, Abonnements kündigen, Event-Listener entfernen
onUnmountedNachdem die Komponente zerstört wurdeAufräumarbeiten bestätigen

Im Blog-Projekt verwenden wir am häufigstenonMounted— um Artikeldaten nach dem Laden der Seite abzurufen.

Lifecycle-Hooks müssen geschrieben werden in<script setup>setup und können nicht innerhalb von async-Funktionen oder bedingten Anweisungen platziert werden. Vue bestimmt anhand der Reihenfolge der Aufrufe, zu welcher Komponente sie gehören.


Grundlegende Verwendung von onMounted

Beispiel

<script setup>
import { ref, onMounted } from 'vue'

const message = ref('Wird geladen...')

// onMounted wird ausgeführt, nachdem die Komponente auf der Seite gemountet wurde
onMounted(() => {
// Zu diesem Zeitpunkt ist das Rendern des DOM abgeschlossen, daher ist es sicher, das DOM zu manipulieren oder Anfragen zu senden.
console.log('Die Komponente wurde eingebunden, kann jetzt mit dem Laden von Daten beginnen')
message.value = 'Laden der Daten abgeschlossen!'
})
</script>

<template>
  <p>{{ message }}</p>
</template>

Eine Komponente kann onMounted mehrmals aufrufen, und sie werden in der Reihenfolge ihrer Registrierung ausgeführt.


JSON-Daten mit fetch laden

Wir werden die Artikeldaten in einer JSON-Datei ablegen und dann fetch in onMounted verwenden, um sie zu laden.

Schritt 1: Eine Datendatei erstellen

Beispiel

// Dateipfad: public/posts.json
[
  {
    "id": 1,
"title": "Vue3 Kompletter Anfängerleitfaden",
"summary": "Von Null an Vue3 Composition API lernen, einschließlich ref, reactive, computed und weiterer Kernkonzepte.",
"content": "<h2>Warum Vue3 lernen?</h2><p>Vue3 ist eines der derzeit beliebtesten Frontend-Frameworks...</p>",
    "category": "Vue",
    "date": "2024-05-10"
  },
  {
    "id": 2,
"title": "Asynchrone Programmierung in JavaScript erklärt"
"summary": "Ein Artikel zum Verständnis von Promise, async/await, Event-Loop und Microtask-Queue.",
"content": "<h2>Was ist asynchron?</h2><p>JS ist single-threaded...</p>",
    "category": "JavaScript",
    "date": "2024-05-08"
  },
  {
    "id": 3,
"title": "CSS Grid Layout in Aktion"
"summary": "Komplexe responsive Layouts lassen sich mit CSS Grid einfach umsetzen.",
"content": "<h2>Erste Schritte mit Grid</h2><p>Grid ist ein zweidimensionales Layout-System...</p>",
    "category": "CSS",
    "date": "2024-05-05"
  }
]

Die JSON-Datei wird impublic/Verzeichnis. Vite stellt sie direkt als statische Datei bereit. Im Browser können Sie darauf zugreifen über/posts.jsondirekt. Dateien, die in public abgelegt werden, werden nicht kompiliert; sie werden unverändert in die Build-Ausgabe kopiert.

Schritt 2: Daten in der Komponente abrufen

Beispiel

<!-- Dateipfad: src/views/HomeView.vue -->
<script setup>
import { ref, onMounted } from 'vue'
import BlogCard from '../components/BlogCard.vue'
import CategoryFilter from '../components/CategoryFilter.vue'

const articles = ref([]) // anfängliches leeres Array
const isLoading = ref(true) // Ladezustand
const error = ref(null) // Fehlermeldung

// Artikeldaten asynchron laden
async function fetchPosts() {
  isLoading.value = true
  error.value = null
  try {
    const response = await fetch('/posts.json')
// Prüfen, ob die Antwort erfolgreich ist (löst bei 404 oder 500 einen Fehler aus)
    if (!response.ok) {
throw new Error(`Laden fehlgeschlagen: HTTP ${response.status}`)
    }
    const data = await response.json()
    articles.value = data
  } catch (err) {
    error.value = err.message
console.error('Fehler beim Laden der Artikeldaten:', err)
  } finally {
    isLoading.value = false
  }
}

// Daten sofort nach dem Mounten der Komponente laden
onMounted(() => {
  fetchPosts()
})
</script>

<template>
  <div class="home">
    <h2>Neueste Artikel</h2>

    <!-- Ladezustand -->
    <p v-if="isLoading" class="status-msg">Wird geladen, bitte warten...</p>

    <!-- Fehlerzustand -->
    <p v-else-if="error" class="status-msg error">
Laden fehlgeschlagen: {{ error }}
      <button @click="fetchPosts">Erneut versuchen</button>
    </p>

    <!-- Leerer Datenzustand -->
    <p v-else-if="articles.length === 0" class="status-msg">
Noch keine Artikel, bitte schauen Sie bald wieder vorbei.
    </p>

    <!-- Normale Datenanzeige -->
    <template v-else>
      <div class="article-grid">
        <BlogCard
         v-for="article in articles"
         :key="article.id"
         :id="article.id"
         :title="article.title"
         :summary="article.summary"
         :date="article.date"
         :category="article.category"
       />
      </div>
    </template>
  </div>
</template>

<style scoped>
.status-msg {
  text-align: center;
  padding: 60px 0;
  font-size: 16px;
  color: #999;
}
.error { color: #e74c3c; }
.error button {
  margin-left: 10px;
  padding: 4px 12px;
  cursor: pointer;
}
</style>

Umgang mit drei Zuständen asynchroner Anfragen

Jede Datenanfrage sollte die folgenden drei UI-Zustände abdecken, andernfalls ist die Benutzererfahrung schlecht:

StateWann es erscheintUI-Darstellung
Wird geladenNachdem die Anfrage gesendet wurde, bevor die Antwort zurückkehrtLadeanimation, Skeleton-Screen
ErfolgDaten werden korrekt zurückgegebenInhalt normal rendern
FehlerNetzwerkfehler, ServerausnahmeFehlermeldung + Wiederholen-Button

Du kannst auch einen vierten Zustand behandeln—leere Daten(die Anfrage ist erfolgreich, gibt aber ein leeres Array zurück), wodurch Nutzer eine klare Nachricht statt einer leeren Seite erhalten.


Praktisch: Stelle die Detailseite ebenfalls auf Fetch-Laden um

Die Detailseite muss den entsprechenden Artikel anhand der ID in der URL aus dem JSON finden.

Du kannst die Logik zum Laden der Daten wiederverwenden—rufe auch fetch auf der Detailseite auf und filtere dann.

Beispiel

<!-- Dateipfad: src/views/PostView.vue -->
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRoute, RouterLink } from 'vue-router'

const route = useRoute()
const id = Number(route.params.id)

const posts = ref([]) // alle Beiträge
const isLoading = ref(true)
const error = ref(null)

// Aktuellen Artikel anhand der ID finden
const article = computed(() => {
  return posts.value.find(p => p.id === id)
})

// Alle Artikeldaten laden
async function fetchPosts() {
  isLoading.value = true
  try {
    const res = await fetch('/posts.json')
if (!res.ok) throw new Error('Failed to load')
    posts.value = await res.json()
  } catch (err) {
    error.value = err.message
  } finally {
    isLoading.value = false
  }
}

onMounted(() => {
  fetchPosts()
})
</script>

<template>
  <div class="post-view">
    <p v-if="isLoading">Wird geladen...</p>
    <p v-else-if="error">Laden fehlgeschlagen: {{ error }}</p>
    <div v-else-if="!article">
      <h2>Artikel existiert nicht</h2>
      <RouterLink to="/">Zurück zur Startseite</RouterLink>
    </div>
    <article v-else>
      <span class="category-tag">{{ article.category }}</span>
      <h1>{{ article.title }}</h1>
      <time>{{ article.date }}</time>
      <div class="content" v-html="article.content"></div>
      <RouterLink to="/">← Zurück zur Startseite</RouterLink>
    </article>
  </div>
</template>

Kapitelzusammenfassung

In diesem Kapitel hast du den wesentlichsten Vue3-Lifecycle-Hook onMounted gemeistert, fetch verwendet, um JSON-Daten aus dem public-Verzeichnis zu laden, und gelernt, wie man die vier UI-Zustände einer Anfrage behandelt (Laden/Erfolg/Fehler/Leer).

Jetzt werden die Blogdaten asynchron aus einer externen JSON-Datei geladen, was der Arbeitsweise echter Projekte näher kommt.

Andere Erweiterungen