JAVASCRIPT
Reacting to Data Changes with watch and watchEffect in Vue 3
Execute side effects when reactive data changes using `watch` for specific sources and `watchEffect` for automatic dependency tracking in Vue 3.
<script setup>
import { ref, reactive, watch, watchEffect } from 'vue';
const count = ref(0);
const name = ref('Alice');
const user = reactive({
firstName: 'John',
lastName: 'Doe',
age: 30
});
// watch a single ref
watch(count, (newCount, oldCount) => {
console.log(`Count changed from ${oldCount} to ${newCount}`);
// Perform an action, e.g., fetch data
if (newCount > 5) {
console.log('Count is now greater than 5!');
}
});
// watch multiple refs
watch([name, () => user.firstName], ([newName, newFirstName], [oldName, oldFirstName]) => {
console.log(`Name changed from "${oldName}" to "${newName}"`);
console.log(`User first name changed from "${oldFirstName}" to "${newFirstName}"`);
});
// watch a reactive object property (requires a getter function)
watch(() => user.age, (newAge, oldAge) => {
console.log(`User age changed from ${oldAge} to ${newAge}`);
});
// watch a reactive object deeply
watch(user, (newUser, oldUser) => {
console.log('User object changed deeply:', newUser, oldUser);
}, { deep: true }); // Important for deep changes
// watchEffect: automatically tracks dependencies
watchEffect(() => {
console.log(`watchEffect: Current count is ${count.value} and name is ${name.value}`);
// This effect will re-run whenever count or name changes
});
// Cleanup for watchEffect
const stopWatchEffect = watchEffect((onCleanup) => {
// Simulate an async operation
const id = setTimeout(() => {
console.log(`watchEffect with cleanup: Fetching data for count ${count.value}`);
}, 1000);
onCleanup(() => {
// This will be called before the effect re-runs or component unmounts
console.log(`watchEffect cleanup: Clearing timeout for count ${count.value}`);
clearTimeout(id);
});
});
// Stop a watch manually if needed
// stopWatchEffect();
function increment() {
count.value++;
}
function changeName() {
name.value = name.value === 'Alice' ? 'Bob' : 'Alice';
}
function increaseAge() {
user.age++;
}
function changeLastName() {
user.lastName = user.lastName === 'Doe' ? 'Smith' : 'Doe';
}
</script>
<template>
<div>
<h2>Watchers Example</h2>
<p>Count: {{ count }}</p>
<button @click="increment">Increment Count</button>
<p>Name: {{ name }}</p>
<button @click="changeName">Change Name</button>
<p>User: {{ user.firstName }} {{ user.lastName }} (Age: {{ user.age }})</p>
<button @click="increaseAge">Increase Age</button>
<button @click="changeLastName">Change Last Name (deep watch)</button>
<p>Check console for watch logs.</p>
</div>
</template>
How it works: This snippet demonstrates the two primary ways to react to data changes in Vue 3's Composition API: `watch` and `watchEffect`. `watch` allows you to explicitly observe one or more reactive data sources (refs, reactive objects, or getter functions) and execute a callback when they change, providing access to both new and old values. `watchEffect` automatically tracks any reactive dependencies accessed during its initial run and re-executes whenever those dependencies change, also offering a cleanup function for side effects.