Skip to content

Kapitel 13: Watch & WatchEffect (Beobachter)

📙 Lernziel: watch() und watchEffect() meistern - Datenänderungen überwachen!


13.1 watch() Grundlagen

watch() überwacht reaktive Daten und führt bei Änderung eine Funktion aus.

Syntax:

javascript
watch(quelle, callback, optionen)

Einfaches Beispiel:

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

const count = ref(0)
const message = ref('Hallo')

// watch() - Überwacht count
watch(count, (newValue, oldValue) => {
  console.log(`count geändert: ${oldValue} → ${newValue}`)
})

// watch() - Überwacht message
watch(message, (newValue, oldValue) => {
  console.log(`message geändert: ${oldValue} → ${newValue}`)
})

// count erhöhen
const increment = () => {
  count.value++
}

// message ändern
const changeMessage = () => {
  message.value = 'Vue 3 ist toll!'
}
</script>

<template>
  <p>Zähler: {{ count }}</p>
  <button @click="increment">Erhöhen</button>
  
  <p>Nachricht: {{ message }}</p>
  <button @click="changeMessage">Nachricht ändern</button>
</template>

Wichtig:

  • watch() erhält newValue und oldValue
  • ✅ Reagiert nur auf Änderungen der überwachten Quelle

13.2 watch() für mehrere Quellen

Mehrere Quellen gleichzeitig überwachen:

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

const firstName = ref('')
const lastName = ref('')

// Array von Quellen
watch([firstName, lastName], (newValues, oldValues) => {
  console.log('Vorname oder Nachname geändert!')
  console.log('Neu:', newValues)
  console.log('Alt:', oldValues)
})
</script>

<template>
  <div>
    <label>Vorname: <input v-model="firstName" /></label><br>
    <label>Nachname: <input v-model="lastName" /></label><br>
    <p>Vollständiger Name: {{ firstName }} {{ lastName }}</p>
  </div>
</template>

13.3 watch() für Objekte (Tiefenüberwachung)

Problem: watch() überwacht standardmäßig nur Referenzänderungen.

Lösung: deep: true Option

vue
<script setup>
import { reactive, watch } from 'vue'

const user = reactive({
  name: 'Max',
  address: {
    city: 'Berlin',
    street: 'Hauptstraße'
  }
})

// ❌ Funktioniert nicht für tiefe Änderungen
watch(user, () => {
  console.log('user geändert')
})

// ✅ Mit deep: true
watch(user, () => {
  console.log('user (tief) geändert')
}, { deep: true })

// ✅ Bessere Lösung: Nur spezifisches Property überwachen
watch(() => user.address.city, (newCity) => {
  console.log('Stadt geändert:', newCity)
})
</script>

<template>
  <div>
    <p>Name: {{ user.name }}</p>
    <p>Stadt: {{ user.address.city }}</p>
    <button @click="user.address.city = 'München'">Stadt ändern</button>
  </div>
</template>

Empfehlung: Nutze () => user.address.city statt deep: true (effizienter)!


13.4 watchEffect() Grundlagen

watchEffect() führt eine Funktion sofort aus und überwacht alle darin verwendeten reaktiven Daten.

Unterschied zu watch():

Merkmalwatch()watchEffect()
Sofortige Ausführung❌ Nein✅ Ja
Explizite Quelle✅ Ja❌ Nein (automatisch)
newValue / oldValue✅ Ja❌ Nein

Beispiel:

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

const count = ref(0)
const message = ref('Hallo')

// watchEffect() - Führt sofort aus und überwacht Abhängigkeiten
watchEffect(() => {
  console.log(`count: ${count.value}, message: ${message.value}`)
})

// count erhöhen
const increment = () => {
  count.value++
}

// message ändern
const changeMessage = () => {
  message.value = 'Vue 3 ist toll!'
}
</script>

<template>
  <p>Zähler: {{ count }}</p>
  <button @click="increment">Erhöhen</button>
  
  <p>Nachricht: {{ message }}</p>
  <button @click="changeMessage">Nachricht ändern</button>
</template>

13.5 watch() vs watchEffect() - Wann was nutzen?

watch() nutzen wenn:

  • ✅ Du brauchst oldValue und newValue
  • ✅ Du willst die Quelle explizit angeben
  • ✅ Du willst nicht sofort ausführen (nur bei Änderung)

watchEffect() nutzen wenn:

  • ✅ Du willst sofort ausführen
  • ✅ Du hast mehrere Abhängigkeiten (automatische Erkennung)
  • ✅ Du brauchst keine oldValue

Beispiel - API Aufruf:

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

const userId = ref(1)
const userData = ref(null)

// watch() - API Aufruf nur wenn userId sich ändert
watch(userId, async (newId) => {
  const response = await fetch(`https://jsonplaceholder.typicode.com/users/${newId}`)
  userData.value = await response.json()
}, { immediate: true }) // Sofort ausführen
</script>

<template>
  <div>
    <button @click="userId++">Nächster User</button>
    <div v-if="userData">
      <h2>{{ userData.name }}</h2>
      <p>Email: {{ userData.email }}</p>
    </div>
  </div>
</template>

13.6 Übung: Suchfeld mit watch()

Aufgabe: Erstelle ein Suchfeld, das bei Eingabe eine API abfragt (Debouncing).

Lösung:

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

const searchQuery = ref('')
const results = ref([])
const isLoading = ref(false)
let timeoutId = null

// watch() mit Debouncing
watch(searchQuery, (newQuery) => {
  if (newQuery.trim() === '') {
    results.value = []
    return
  }
  
  // Debouncing: Warte 500ms vor API Aufruf
  clearTimeout(timeoutId)
  timeoutId = setTimeout(async () => {
    isLoading.value = true
    try {
      const response = await fetch(`https://api.example.com/search?q=${newQuery}`)
      results.value = await response.json()
    } catch (error) {
      console.error('Fehler:', error)
    } finally {
      isLoading.value = false
    }
  }, 500)
})
</script>

<template>
  <div>
    <input 
      v-model="searchQuery" 
      placeholder="Suchen..."
    />
    <div v-if="isLoading">Lädt...</div>
    <ul v-else>
      <li v-for="result in results" :key="result.id">
        {{ result.name }}
      </li>
    </ul>
  </div>
</template>

✅ Zusammenfassung

In diesem Kapitel hast du gelernt:

  • watch() Grundlagen
  • watch() für mehrere Quellen
  • watch() für Objekte (deep: true)
  • watchEffect() Grundlagen
  • ✅ Unterschied zwischen watch() und watchEffect()
  • ✅ Praxis: Suchfeld mit Debouncing

🎯 Nächster Schritt: In Kapitel 14 lernst du Stilbindung (Class & Style)!


← Zurück zu Kapitel 12: Computed PropertiesWeiter zu Kapitel 14: Stilbindung →

Frei für alle Anfänger