Skip to content

Kapitel 22: Composition API (Teil 2) - Reaktive Grundlagen

📙 Lernziel: ref() und reactive() meistern - reaktive Daten in Vue 3!


22.1 Was ist Reaktivität?

Reaktivität bedeutet: Wenn sich Daten ändern, wird die Benutzeroberfläche automatisch aktualisiert.

Beispiel (ohne Reaktivität):

javascript
let count = 0
count++  // UI wird NICHT aktualisiert

Beispiel (mit Reaktivität - Vue 3):

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

const count = ref(0)
count.value++  // UI wird AUTOMATISCH aktualisiert!
</script>

<template>
  <p>{{ count }}</p>
</template>

22.2 ref() - Für primitive Werte

ref() macht primitive Werte (number, string, boolean) reaktiv.

Syntax:

javascript
import { ref } from 'vue'

const variable = ref(initialWert)

Beispiele:

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

// Primitive Werte
const count = ref(0)          // number
const message = ref('Hallo')   // string
const isVisible = ref(true)     // boolean
const todoList = ref([])       // array
const user = ref({})           // object

// Zugriff und Änderung (mit .value!)
console.log(count.value)  // 0
count.value++
console.log(count.value)  // 1

message.value = 'Vue 3 ist toll!'
isVisible.value = false
todoList.value.push('Neue Aufgabe')
user.value = { name: 'Max', age: 25 }
</script>

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

Wichtig:

  • ✅ Im <script>: Immer .value verwenden!
  • ✅ Im <template>: Nie .value verwenden (Vue macht das automatisch)!

22.3 reactive() - Für Objekte

reactive() macht Objekte und Arrays reaktiv (tiefgreifend).

Syntax:

javascript
import { reactive } from 'vue'

const objekt = reactive({ ... })

Beispiele:

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

// Objekte
const state = reactive({
  count: 0,
  message: 'Hallo',
  isVisible: true
})

// Zugriff und Änderung (OHNE .value!)
console.log(state.count)  // 0
state.count++
console.log(state.count)  // 1

state.message = 'Vue 3 ist toll!'
state.isVisible = false

// Arrays
const todos = reactive(['Lernen', 'Sport'])
todos.push('Einkaufen')
todos[0] = 'Vue 3 lernen'

// Verschachtelte Objekte (auch reaktiv!)
const user = reactive({
  name: 'Max',
  address: {
    city: 'Berlin',
    street: 'Hauptstraße'
  }
})
user.address.city = 'München'  // Auch reaktiv!
</script>

<template>
  <p>{{ state.count }}</p>
  <p>{{ state.message }}</p>
  <ul>
    <li v-for="todo in todos" :key="todo">{{ todo }}</li>
  </ul>
</template>

Vorteile von reactive():

  • ✅ Kein .value nötig
  • ✅ Tiefgreifende Reaktivität (auch verschachtelte Objekte)

22.4 ref() vs reactive() - Wann was nutzen?

Empfehlungen:

SituationEmpfehlungBeispiel
Primitive Werte (number, string, boolean)ref()const count = ref(0)
Einfache Objekte/Arraysreactive()const state = reactive({ ... })
Komplextes State-Objektreactive()const state = reactive({ user: {...}, posts: [...] })
Einzelne Werte (auch Objekte)ref()const user = ref({ ... })

Migrierung zwischen ref() und reactive():

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

// ref() zu reactive()
const userRef = ref({ name: 'Max', age: 25 })
const userReactive = reactive(userRef.value)

// reactive() zu ref() (mit toRefs() - später)
const state = reactive({ count: 0, message: 'Hallo' })
const stateAsRefs = toRefs(state)  // Macht jedes Property zu ref()
</script>

Meinung der Vue-Community:

  • Viele Entwickler nutzen nur ref() (einheitlicher)
  • reactive() ist nützlich für komplexe State-Objekte

22.5 Reaktivität "Lost" (Verlust der Reaktivität)

Problem: Reaktivität geht verloren, wenn du Eigenschaften destrukturierst.

❌ Falsch (Reaktivität verloren):

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

const state = reactive({ count: 0, message: 'Hallo' })

// ❌ Destrukturierung (Reaktivität verloren!)
const { count, message } = state

count++  // UI wird NICHT aktualisiert!
</script>

<template>
  <p>{{ count }}</p>  <!-- Ändert sich nicht! -->
</template>

✅ Richtig (mit toRefs()):

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

const state = reactive({ count: 0, message: 'Hallo' })

// ✅ toRefs() (Reaktivität erhalten!)
const { count, message } = toRefs(state)

count.value++  // UI wird aktualisiert!
</script>

<template>
  <p>{{ count }}</p>  <!-- Ändert sich! -->
</template>

Oder einfach state. verwenden:

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

const state = reactive({ count: 0, message: 'Hallo' })

// ✅ Einfach state. verwenden
state.count++  // UI wird aktualisiert!
</script>

<template>
  <p>{{ state.count }}</p>  <!-- Ändert sich! -->
</template>

22.6 toRef() und toRefs()

toRef() - Macht eine einzelne Eigenschaft reaktiv (Ref).

toRefs() - Macht alle Eigenschaften reaktiv (Refs).

Beispiele:

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

const state = reactive({ count: 0, message: 'Hallo' })

// toRef() (einzelne Eigenschaft)
const countRef = toRef(state, 'count')
countRef.value++  // state.count wird auch aktualisiert!

// toRefs() (alle Eigenschaften)
const { count, message } = toRefs(state)
count.value++  // state.count wird auch aktualisiert!
message.value = 'Vue 3'  // state.message wird auch aktualisiert!
</script>

Anwendungsfall (Composables):

javascript
// composables/useCounter.js
import { reactive, toRefs } from 'vue'

export function useCounter() {
  const state = reactive({
    count: 0,
    step: 1
  })
  
  const increment = () => {
    state.count += state.step
  }
  
  const decrement = () => {
    state.count -= state.step
  }
  
  // toRefs() damit Destrukturierung möglich ist
  return {
    ...toRefs(state),
    increment,
    decrement
  }
}

Verwendung:

vue
<script setup>
import { useCounter } from '../composables/useCounter.js'

// ✅ Destrukturierung (dank toRefs() reaktiv!)
const { count, step, increment, decrement } = useCounter()
</script>

<template>
  <p>Zähler: {{ count }}</p>
  <button @click="increment">+</button>
  <button @click="decrement">-</button>
</template>

22.7 Übung: Counter mit ref() und reactive()

Aufgabe: Erstelle einen Counter, der ref() und reactive() nutzt.

Lösung:

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

// Mit ref()
const count = ref(0)

// Mit reactive()
const state = reactive({
  step: 1,
  min: 0,
  max: 100
})

const increment = () => {
  if (count.value < state.max) {
    count.value += state.step
  }
}

const decrement = () => {
  if (count.value > state.min) {
    count.value -= state.step
  }
}

const reset = () => {
  count.value = 0
}
</script>

<template>
  <div class="counter">
    <h2>Zähler: {{ count }}</h2>
    <div>
      <button @click="decrement">-</button>
      <span>{{ count }}</span>
      <button @click="increment">+</button>
    </div>
    <div>
      <label>Schritt: <input type="number" v-model="state.step" min="1" max="10" /></label>
      <label>Minimum: <input type="number" v-model="state.min" /></label>
      <label>Maximum: <input type="number" v-model="state.max" /></label>
    </div>
    <button @click="reset">Zurücksetzen</button>
  </div>
</template>

<style scoped>
.counter {
  border: 1px solid #42b883;
  border-radius: 8px;
  padding: 20px;
  max-width: 400px;
  margin: 0 auto;
}

.counter div {
  margin: 10px 0;
}

button {
  padding: 5px 15px;
  margin: 0 5px;
  background: #42b883;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

label {
  display: block;
  margin: 5px 0;
}
</style>

✅ Zusammenfassung

In diesem Kapitel hast du gelernt:

  • ✅ Was Reaktivität ist
  • ref() für primitive Werte nutzen
  • reactive() für Objekte/Arrays nutzen
  • ✅ Unterschied zwischen ref() und reactive()
  • ✅ Reaktivität "Lost" vermeiden (mit toRefs())
  • toRef() und toRefs() nutzen
  • ✅ Praxis: Counter mit ref() und reactive()

🎯 Nächster Schritt: In Kapitel 23 lernst du computed() und watch() in Composition API!


← Zurück zu Kapitel 21: Composition API EinführungWeiter zu Kapitel 23: computed() & watch() →

Frei für alle Anfänger