Vue 3 Composition API
Die Composition API von Vue 3 bietet einen flexibleren und skalierbareren Weg, die Komponentenlogik zu organisieren, besonders für komplexe Anwendungen.
1. Setup und Basis-Reaktivität
<script setup>
import { ref, reactive } from 'vue'
// ref für primitive Werte
const count = ref(0)
const message = ref('Hallo Vue 3!')
// reactive für Objekte
const user = reactive({
name: 'Mario',
email: 'mario@example.com',
preferences: {
theme: 'dark',
notifications: true
}
})
// Funktionen
const increment = () => {
count.value++ // .value für ref
}
const updateUser = (field, value) => {
user[field] = value // Kein .value für reactive
}
</script>
<template>
<div>
<p>{{ message }}</p>
<p>Count: {{ count }}</p>
<button @click="increment">+1</button>
<p>User: {{ user.name }}</p>
</div>
</template>
2. Computed Properties
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('Mario')
const lastName = ref('Rossi')
const items = ref([
{ name: 'Apfel', price: 1.5, quantity: 3 },
{ name: 'Banane', price: 0.8, quantity: 5 }
])
// Einfaches Computed
const fullName = computed(() => {
return \`\${firstName.value} \${lastName.value}\`
})
// Computed mit Getter und Setter
const fullNameWritable = computed({
get() {
return \`\${firstName.value} \${lastName.value}\`
},
set(newValue) {
const [first, last] = newValue.split(' ')
firstName.value = first
lastName.value = last
}
})
// Computed für Berechnungen
const totalPrice = computed(() => {
return items.value.reduce((sum, item) => {
return sum + (item.price * item.quantity)
}, 0).toFixed(2)
})
</script>
3. Watchers
<script setup>
import { ref, watch, watchEffect } from 'vue'
const searchQuery = ref('')
const selectedId = ref(null)
const user = ref(null)
// Einzelnen Wert beobachten
watch(searchQuery, (newValue, oldValue) => {
console.log(\`Suche geändert: \${oldValue} -> \${newValue}\`)
// Debounced-Suche
fetchResults(newValue)
})
// Watch mit Optionen
watch(selectedId, async (newId) => {
if (newId) {
user.value = await fetchUser(newId)
}
}, { immediate: true }) // Sofort ausführen
// Mehrere Werte beobachten
watch(
[firstName, lastName],
([newFirst, newLast], [oldFirst, oldLast]) => {
console.log('Name geändert')
}
)
// watchEffect - verfolgt Abhängigkeiten automatisch
watchEffect(() => {
console.log(\`User: \${user.value?.name}\`)
// Verfolgt user.value automatisch
})
// Cleanup
watchEffect((onCleanup) => {
const controller = new AbortController()
fetchData(controller.signal)
onCleanup(() => {
controller.abort()
})
})
</script>
4. Lifecycle Hooks
<script setup>
import {
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount
} from 'vue'
onBeforeMount(() => {
console.log('Vor dem Mount')
})
onMounted(() => {
console.log('Komponente gemountet')
// Daten laden, Listener einrichten
window.addEventListener('resize', handleResize)
})
onUpdated(() => {
console.log('DOM aktualisiert')
})
onBeforeUnmount(() => {
console.log('Vor dem Unmount')
})
onUnmounted(() => {
console.log('Komponente unmounted')
// Cleanup
window.removeEventListener('resize', handleResize)
})
</script>
5. Composables (Custom Hooks)
// composables/useFetch.js
import { ref, watchEffect, toValue } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(true)
const fetchData = async () => {
loading.value = true
error.value = null
try {
const response = await fetch(toValue(url))
if (!response.ok) throw new Error('Fetch fehlgeschlagen')
data.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}
watchEffect(() => {
fetchData()
})
return { data, error, loading, refetch: fetchData }
}
// composables/useLocalStorage.js
export function useLocalStorage(key, defaultValue) {
const stored = localStorage.getItem(key)
const data = ref(stored ? JSON.parse(stored) : defaultValue)
watch(data, (newValue) => {
localStorage.setItem(key, JSON.stringify(newValue))
}, { deep: true })
return data
}
// Verwendung in Komponenten
<script setup>
import { useFetch } from '@/composables/useFetch'
import { useLocalStorage } from '@/composables/useLocalStorage'
const { data: posts, loading, error } = useFetch('/api/posts')
const theme = useLocalStorage('theme', 'light')
</script>
6. Provide / Inject
// Eltern-Komponente
<script setup>
import { provide, ref } from 'vue'
const theme = ref('dark')
const toggleTheme = () => {
theme.value = theme.value === 'dark' ? 'light' : 'dark'
}
provide('theme', { theme, toggleTheme })
</script>
// Kind-Komponente (beliebige Tiefe)
<script setup>
import { inject } from 'vue'
const { theme, toggleTheme } = inject('theme')
</script>
<template>
<button @click="toggleTheme">
Aktuell: {{ theme }}
</button>
</template>
Vue 3 Best Practices
- Verwenden Sie
reffür Primitive,reactivefür Objekte - Extrahieren Sie wiederverwendbare Logik in Composables
- Bevorzugen Sie
<script setup>für sauberere Komponenten - Verwenden Sie
toRefundtoRefszum Destrukturieren reaktiver Objekte - Nutzen Sie TypeScript für Type-Safety
Fazit
Die Composition API macht Vue 3 unglaublich leistungsstark und flexibel. Composables ermöglichen es, Logik elegant zu organisieren und wiederzuverwenden.