Zum Inhalt springen

Computed & Watchers

Computed Properties sind abgeleitete Werte, die automatisch neu berechnet werden, wenn sich ihre Abhängigkeiten ändern.

Sie sind ideal für komplexe Berechnungen oder Transformationen, die von reaktiven Daten abhängen.

<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Max')
const lastName = ref('Mustermann')
// Method: Wird bei JEDEM Render aufgerufen
function getFullName() {
console.log('Method aufgerufen')
return firstName.value + ' ' + lastName.value
}
// Computed: Wird nur bei Änderung neu berechnet (gecached)
const fullName = computed(() => {
console.log('Computed aufgerufen')
return firstName.value + ' ' + lastName.value
})
</script>
<script setup>
import { ref, computed } from 'vue'
const items = ref([
{ name: 'Apfel', price: 1.50, quantity: 3 },
{ name: 'Birne', price: 2.00, quantity: 2 }
])
// Einfaches Computed
const itemCount = computed(() => items.value.length)
// Computed mit Logik
const totalPrice = computed(() => {
return items.value.reduce((sum, item) => {
return sum + item.price * item.quantity
}, 0)
})
// Computed für Filterung
const expensiveItems = computed(() => {
return items.value.filter(item => item.price > 1.50)
})
</script>
<script>
export default {
data() {
return {
firstName: 'Max',
lastName: 'Mustermann',
items: []
}
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
},
itemCount() {
return this.items.length
},
totalPrice() {
return this.items.reduce((sum, item) => sum + item.price, 0)
}
}
}
</script>

Standardmäßig sind Computed Properties read-only. Mit Getter und Setter werden sie beschreibbar:

<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Max')
const lastName = ref('Mustermann')
const fullName = computed({
get() {
return firstName.value + ' ' + lastName.value
},
set(newValue) {
const parts = newValue.split(' ')
firstName.value = parts[0]
lastName.value = parts[1] || ''
}
})
// Jetzt möglich:
fullName.value = 'Anna Schmidt' // Setzt firstName und lastName
</script>
  • Abgeleitete Daten
  • Formatierung (Datum, Währung)
  • Filterung & Sortierung
  • Komplexe Bedingungen im Template

Watchers beobachten reaktive Daten und führen Code aus, wenn sich diese ändern.

Sie sind ideal für Side Effects wie API-Aufrufe, DOM-Manipulationen oder das Synchronisieren mit externen Systemen.

<script setup>
import { ref, watch } from 'vue'
const searchQuery = ref('')
const searchResults = ref([])
// Einzelne Ref beobachten
watch(searchQuery, async (newValue, oldValue) => {
console.log(`Suche geändert: ${oldValue} -> ${newValue}`)
if (newValue.length >= 3) {
searchResults.value = await fetchResults(newValue)
}
})
</script>
<script setup>
import { ref, reactive, watch } from 'vue'
const firstName = ref('Max')
const lastName = ref('Mustermann')
// Array von Quellen
watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {
console.log(`Name: ${oldFirst} ${oldLast} -> ${newFirst} ${newLast}`)
})
// Reactive Object Property (Getter-Funktion nötig!)
const user = reactive({ name: 'Max' })
watch(
() => user.name, // Getter-Funktion
(newName) => {
console.log('Name geändert:', newName)
}
)
</script>
<script setup>
import { ref, watch } from 'vue'
const data = ref({ nested: { value: 0 } })
watch(data, (newData) => {
console.log('Data geändert')
}, {
// Sofort beim Setup ausführen (nicht auf Änderung warten)
immediate: true,
// Tief verschachtelte Änderungen beobachten
deep: true,
// Callback nach DOM-Update ausführen
flush: 'post',
// Nur einmal ausführen
once: true
})
</script>
<script setup>
import { ref, reactive, watch } from 'vue'
// Mit ref() - deep: true erforderlich
const user = ref({
profile: { name: 'Max', age: 30 }
})
watch(user, (newUser) => {
console.log('User geändert')
}, { deep: true })
// Mit reactive() - automatisch deep!
const state = reactive({
user: { name: 'Max' }
})
watch(state, (newState) => {
console.log('State geändert') // Automatisch deep
})
</script>

watchEffect() trackt Abhängigkeiten automatisch und führt sofort aus:

<script setup>
import { ref, watchEffect } from 'vue'
const url = ref('/api/users')
const data = ref(null)
// Führt sofort aus UND bei jeder Änderung von url
watchEffect(async () => {
const response = await fetch(url.value)
data.value = await response.json()
})
// Cleanup-Funktion
watchEffect((onCleanup) => {
const controller = new AbortController()
fetch(url.value, { signal: controller.signal })
.then(r => r.json())
.then(d => data.value = d)
onCleanup(() => controller.abort())
})
</script>
Aspektwatch()watchEffect()
AbhängigkeitenExplizit angebenAutomatisch getrackt
AusführungBei ÄnderungSofort + bei Änderung
Alter WertVerfügbarNicht verfügbar
LazyStandardImmer eager
PräzisionGezieltAlle genutzten Refs
<script>
export default {
data() {
return {
searchQuery: '',
user: { name: 'Max' }
}
},
watch: {
// Einfacher Watcher
searchQuery(newValue, oldValue) {
console.log('Suche:', newValue)
},
// Mit Optionen
user: {
handler(newUser) {
console.log('User geändert')
},
deep: true,
immediate: true
}
}
}
</script>
<script setup>
import { ref, watch, watchEffect } from 'vue'
const count = ref(0)
// watch() und watchEffect() geben eine Stop-Funktion zurück
const stopWatch = watch(count, (newCount) => {
console.log('Count:', newCount)
// Automatisch stoppen bei Bedingung
if (newCount >= 10) {
stopWatch()
}
})
// Manuell stoppen
setTimeout(() => {
stopWatch()
}, 5000)
</script>
  • Abgeleitete Daten berechnen
  • Synchrone Operationen
  • Gecachter Rückgabewert
  • Pure Funktionen
const fullName = computed(() =>
first.value + ' ' + last.value
)
<script setup>
import { ref, watch } from 'vue'
const searchQuery = ref('')
const results = ref([])
const isLoading = ref(false)
let timeout = null
watch(searchQuery, (query) => {
// Vorherigen Timer abbrechen
clearTimeout(timeout)
if (query.length < 2) {
results.value = []
return
}
// Debounce: 300ms warten
timeout = setTimeout(async () => {
isLoading.value = true
results.value = await searchAPI(query)
isLoading.value = false
}, 300)
})
</script>

Offizielle Vue Dokumentation:

API Referenz: