Vue.js 3: Composition API und Erweiterte Reaktivität

  • 14 Jan 2026
  • admin
  • 4 min
  • 398

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 ref für Primitive, reactive für Objekte
  • Extrahieren Sie wiederverwendbare Logik in Composables
  • Bevorzugen Sie <script setup> für sauberere Komponenten
  • Verwenden Sie toRef und toRefs zum 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.

Teilen Sie diesen Artikel

Kunden

Noch keine Kommentare. Seien Sie der Erste!

Einen Kommentar hinterlassen

Wird nicht veröffentlicht

Verwandte Artikel