Vue.js Reactivity System
Vue's reactivity system is the core feature that makes data changes automatically update the user interface. Understanding reactivity is essential for building efficient and responsive Vue.js applications.
Available Reactivity Functions
Core Reactivity
- ref()- Create reactive references for primitive values and objects
Additional Reactivity Functions
- reactive()- Create reactive objects and arrays
- computed()- Create computed properties that update automatically
- watch()- Watch reactive data for changes
- watchEffect()- Automatically track dependencies and run effects
Understanding Reactivity
What is Reactivity?
Reactivity means that when data changes, the UI automatically updates to reflect those changes. Vue achieves this through a sophisticated dependency tracking system.
import { ref } from 'vue'
// Create reactive data
const count = ref(0)
// When count changes, any template using it will update automatically
const increment = () => {
  count.value++ // UI updates automatically
}
Reactive vs Non-Reactive Data
// ✅ Reactive - UI will update
const reactiveCount = ref(0)
const reactiveUser = reactive({ name: 'John' })
// ❌ Non-reactive - UI won't update
let plainCount = 0
const plainUser = { name: 'John' }
Core Concepts
Refs vs Reactive
Use ref() for:
- Primitive values (strings, numbers, booleans)
- When you need to replace the entire value
- Single values that might change type
const count = ref(0)
const message = ref('Hello')
const isVisible = ref(true)
Use reactive() for:
- Objects and arrays
- When you want to mutate properties
- Complex data structures
const user = reactive({
  name: 'John',
  age: 30,
  preferences: {
    theme: 'dark'
  }
})
Accessing Reactive Values
In JavaScript (script):
// Refs need .value
console.log(count.value) // 0
count.value = 10
// Reactive objects don't need .value
console.log(user.name) // 'John'
user.name = 'Jane'
In Templates:
<template>
  <!-- Refs are automatically unwrapped -->
  <p>Count: {{ count }}</p>
  <!-- Reactive objects work directly -->
  <p>Name: {{ user.name }}</p>
</template>
Common Patterns
Form Data Management
const form = reactive({
  name: '',
  email: '',
  message: '',
  errors: {}
})
const validateForm = () => {
  form.errors = {}
  if (!form.name) form.errors.name = 'Name is required'
  if (!form.email) form.errors.email = 'Email is required'
}
Loading States
const loading = ref(false)
const data = ref(null)
const error = ref(null)
const fetchData = async () => {
  loading.value = true
  error.value = null
  try {
    const response = await api.getData()
    data.value = response.data
  } catch (err) {
    error.value = err.message
  } finally {
    loading.value = false
  }
}
Computed Properties
const firstName = ref('John')
const lastName = ref('Doe')
// Automatically updates when firstName or lastName changes
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`
})
Watchers
// Watch a single ref
watch(count, (newValue, oldValue) => {
  console.log(`Count changed from ${oldValue} to ${newValue}`)
})
// Watch multiple sources
watch([firstName, lastName], ([newFirst, newLast]) => {
  console.log(`Name changed to ${newFirst} ${newLast}`)
})
// Watch reactive object properties
watch(() => user.name, (newName) => {
  console.log(`User name changed to ${newName}`)
})
Advanced Reactivity
Shallow Reactivity
import { shallowRef, shallowReactive } from 'vue'
// Only the reference is reactive, not nested properties
const shallowUser = shallowRef({ name: 'John', age: 30 })
// Only first-level properties are reactive
const shallowState = shallowReactive({
  count: 0,
  nested: { value: 1 } // This won't be reactive
})
Raw Objects
import { markRaw } from 'vue'
// Prevent an object from being made reactive
const rawObject = markRaw({
  data: 'This will never be reactive'
})
Performance Tips
- Use shallowRef()for large objects that don't need deep reactivity
- Use markRaw()for objects that should never be reactive (like external libraries)
- Prefer computed()over methods for derived data
- Use readonly()to prevent accidental mutations
- Consider shallowReactive()for performance-critical scenarios