Wat is Reactivity?

Reactivity is data die kan veranderen in je component. Denk aan: een teller, een toggle, input waardes, of een lijst die groeit.

Waarom is reactivity nodig?

In Vue refresht je browser niet zoals bij gewone HTML. Als je een normale variabele verandert (bijvoorbeeld let count = 5), dan zie je dat niet op je scherm!

Vue's reactivity-systeem zorgt ervoor dat de UI automatisch updatet wanneer reactive data verandert. Zonder reactivity zie je niks gebeuren.

Wanneer gebruik je reactivity?

  • Teller die omhoog/omlaag gaat
  • Modal die open/dicht gaat
  • Input waardes onthouden
  • Lijst waar items aan toegevoegd worden
  • Alles wat op je scherm moet veranderen!

Let op: Een normale variabele werkt NIET reactief in Vue:

let count = 0
count = count + 1  // Verandert wel, maar de UI updatet niet!

Je hebt ref() of reactive() nodig om Vue te laten weten: "Hey, herrender de UI!"

ref() — de eerste keus

Om reactivity te gebruiken, importeer je ref uit Vue:

import { ref } from 'vue'

Basis Syntax

const state = ref(beginWaarde)
  • state — Een reactive container
  • state.value — De huidige waarde (in JavaScript)
  • {{ state }} — In de template hoef je .value NIET te schrijven
  • beginWaarde — Startwaarde (bijv. 0, "", [], een object)

Eerste Voorbeeld: Counter

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

const count = ref(0)

const increment = () => {
  count.value++   // ⚠️ .value in JS
}
</script>

<template>
  <p>Count: {{ count }}</p> <!-- ✅ geen .value in template -->
  <button @click="increment">+1</button>
</template>

Wat gebeurt er?

  1. count start op 0
  2. Bij klik wordt count.value++ uitgevoerd
  3. Vue's reactivity-systeem detecteert de wijziging
  4. De UI updatet automatisch — alleen het stukje dat veranderd is

De grote valkuil voor beginners: in JavaScript moet je .value gebruiken, in de template NIET.

// JavaScript
count.value++          // ✅
count++                // ❌ werkt niet

// Template
{{ count }}            // ✅
{{ count.value }}      // ❌ werkt wel, maar onnodig

Zie de cycle in actie

Wat betekent "Vue updatet de UI automatisch"? Hieronder zie je het visueel. Er staat een Profile component met twee soorten state: een naam en een status. Verander één van beide — typen, klikken, maakt niet uit — en kijk hoe het diagram links de cycle doorloopt.

De Cycle

1
Gebruiker doet iets
Typt, klikt, toggelt... en muteert een ref
2
Vue detecteert de wijziging
De reactive Proxy ziet dat .value is geüpdatet
3
Alleen relevante delen renderen
Vue weet precies welke template-stukjes deze ref gebruiken
4
DOM wordt geüpdatet
Het scherm laat de nieuwe waarde zien
↑ klaar — wachten op de volgende actie

Het Profile Component

👩
Hoi, Anna!
Available
Update Log 0 updates
Typ in naam of klik op de toggle om de cycle te starten...

Het verschil met React: in React draait bij elke state-wijziging de hele component-functie opnieuw. In Vue draait je <script setup> maar één keer bij het mounten — daarna update Vue alleen de specifieke template-stukjes die de geüpdatete ref gebruiken. Dat is wat Vue's reactivity-systeem zo efficiënt maakt.

Objecten & Arrays met ref()

Het mooie van ref() is dat het voor alles werkt — niet alleen voor primitives. Een object of array? Gewoon in ref() stoppen.

Object in ref

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

const user = ref({
  name: 'Anna',
  age: 25,
  hobbies: ['lezen', 'gamen']
})

const birthday = () => {
  user.value.age++              // ✅ property muteren
}

const rename = () => {
  user.value.name = 'Bram'      // ✅ property muteren
}

const replaceUser = () => {
  user.value = { name: 'Chloé', age: 30, hobbies: [] }  // ✅ hele object vervangen mag
}
</script>

<template>
  <p>{{ user.name }} is {{ user.age }}</p>
  <button @click="birthday">Verjaardag!</button>
</template>

Hoe onthoud je het?

  • In JS gebruik je .value om bij het object te komen
  • Daarna werk je gewoon met properties: user.value.name = 'Bram'
  • In templates schrijf je {{ user.name }} — geen .value

Array in ref

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

const todos = ref(['Boodschappen', 'Vue leren'])

const addTodo = (text) => {
  todos.value.push(text)        // ✅ muteren mag
}

const removeFirst = () => {
  todos.value.shift()           // ✅
}

const clearAll = () => {
  todos.value = []              // ✅ hele array vervangen mag
}
</script>

Goed nieuws: Anders dan in React mag je arrays en objecten in Vue gewoon muteren met push, splice, etc. Vue's reactivity-systeem detecteert het. Je hoeft niet "een nieuwe array te maken" zoals [...items, nieuw] — al mag dat ook.

State Updaten — alle manieren

Primitives

const count = ref(0)

// Direct toewijzen
count.value = 5

// Berekenen
count.value = count.value + 1
count.value++

Objecten

const user = ref({ name: 'Anna' })

// Property aanpassen
user.value.name = 'Bram'

// Hele object vervangen
user.value = { name: 'Chloé' }

Arrays

const items = ref([])

// Toevoegen
items.value.push('nieuw')

// Verwijderen
items.value = items.value.filter(i => i !== 'oud')

// Vervangen
items.value = ['a', 'b', 'c']

Praktische Voorbeelden

Toggle (aan/uit)

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

const isOn = ref(false)
</script>

<template>
  <p>Status: {{ isOn ? 'Aan' : 'Uit' }}</p>
  <button @click="isOn = !isOn">Toggle</button>
</template>

Input Waarde (met v-model)

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

const name = ref('')
</script>

<template>
  <input v-model="name" placeholder="Typ je naam" />
  <p>Hallo, {{ name }}!</p>
</template>

Met v-model heb je geen event handler nodig — Vue regelt two-way binding voor je. Dit scheelt veel code vergeleken met React.

Lijst met Items

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

const todos = ref([])
const input = ref('')

const addTodo = () => {
  if (input.value.trim()) {
    todos.value.push(input.value)
    input.value = ''
  }
}
</script>

<template>
  <input v-model="input" />
  <button @click="addTodo">Add</button>
  <ul>
    <li v-for="(todo, i) in todos" :key="i">{{ todo }}</li>
  </ul>
</template>

reactive() — bestaat ook, maar skip dit

In tutorials kom je soms reactive() tegen. Dat is een tweede manier om reactive state te maken, speciaal voor objecten. Het ziet er zo uit:

import { reactive } from 'vue'

const user = reactive({ name: 'Anna', age: 25 })
user.age++   // geen .value nodig

Waarom je het beter NIET gebruikt:

  • Destructuring breekt reactivity: const { age } = userage is geen reactive meer
  • Je mag het object niet vervangen: user = { ... } verbreekt de reactivity
  • Werkt niet voor primitives (alleen objecten/arrays)
  • De rest van het Vue-ecosysteem (composables, VueUse) gebruikt refs — mixen is verwarrend

Conclusie: reactive() is niet deprecated, maar de community is grotendeels overgestapt op "altijd ref()". Je hoeft het alleen te herkennen in oudere code — zelf gebruiken hoeft niet.

Belangrijke Regels

  • In JS gebruik je .value, in templates niet
  • ref() werkt voor alles — primitives, objecten, arrays
  • Arrays en objecten muteren mag (push, splice) — Vue detecteert het
  • Hele objecten/arrays vervangen mag ook (user.value = nieuwObject)
  • Reactivity werkt alleen op refs — niet op losse variabelen

Veelgemaakte Fouten

Fout — .value vergeten in JS:

const count = ref(0)
count++              // ❌ werkt niet (count is een ref-object)
console.log(count)   // ❌ logt de ref, niet 0

Goed:

count.value++       // ✅
console.log(count.value)  // ✅ logt 0

Fout — .value vergeten bij property:

const user = ref({ name: 'Anna' })
user.name = 'Bram'         // ❌ user is een ref, niet het object
console.log(user.name)     // ❌ undefined

Goed:

user.value.name = 'Bram'   // ✅
console.log(user.value.name)  // ✅ 'Bram'

Fout — gewone variabele i.p.v. ref:

<script setup>
let count = 0    // ❌ niet reactive
</script>

<template>
  <p>{{ count }}</p>
  <button @click="count++">+1</button>  <!-- UI updatet niet -->
</template>

Goed:

<script setup>
import { ref } from 'vue'
const count = ref(0)    // ✅ reactive
</script>