JAVASCRIPT
Reacting to Data Changes with Vue 3 Watchers (`watch` and `watchEffect`)
Implement Vue 3 watchers (`watch` and `watchEffect`) to perform side effects in response to reactive data changes, with deep watching and immediate options.
<script setup>
import { ref, watch, watchEffect } from 'vue';
const counter = ref(0);
const searchTerm = ref('');
const userData = ref({ name: 'Alice', age: 30 });
const message = ref('');
// Using `watch` to react to a specific ref change
watch(counter, (newVal, oldVal) => {
console.log(`Counter changed from ${oldVal} to ${newVal}`);
message.value = `Counter is now ${newVal}`;
// Perform side effect, e.g., save to localStorage, make an API call
if (newVal > 5) {
console.log('Counter exceeded 5!');
}
});
// Using `watch` with multiple sources (array) and deep option
watch([searchTerm, () => userData.value.age], ([newSearch, newAge], [oldSearch, oldAge]) => {
console.log(`Search term changed from '${oldSearch}' to '${newSearch}'`);
console.log(`User age changed from ${oldAge} to ${newAge}`);
// Simulate fetching data based on search term or age
if (newSearch.length > 2) {
console.log(`Searching for '${newSearch}'...`);
}
if (newAge < 18) {
console.warn('User is underage!');
}
}, { deep: true, immediate: true }); // `immediate: true` runs the watcher immediately on setup
// Using `watchEffect` for automatic dependency tracking
// Runs immediately, and re-runs whenever any reactive dependency inside it changes.
watchEffect(() => {
const currentName = userData.value.name;
console.log(`WatchEffect: User's current name is ${currentName}.`);
// This will re-run if userData.value.name changes
// If `counter.value` was also used here, it would also become a dependency.
});
function incrementCounter() {
counter.value++;
}
function changeNameAndAge() {
userData.value.name = 'Bob';
userData.value.age = 15; // Triggers age watcher
}
</script>
<template>
<div>
<h1>Vue 3 Watchers Example</h1>
<p>Counter: {{ counter }}</p>
<button @click="incrementCounter">Increment Counter</button>
<p v-if="message">{{ message }}</p>
<hr />
<input type="text" v-model="searchTerm" placeholder="Enter search term" />
<p>Current Search Term: {{ searchTerm }}</p>
<hr />
<p>User Name: {{ userData.name }}</p>
<p>User Age: {{ userData.age }}</p>
<button @click="changeNameAndAge">Change User Name & Age</button>
</div>
</template>
How it works: Vue 3 provides `watch` and `watchEffect` to perform side effects in response to changes in reactive state. `watch` explicitly takes one or more reactive sources (a ref, reactive object, or getter function) and a callback. It receives both the new and old values and gives fine-grained control over when it runs (e.g., `deep` for nested object changes, `immediate` to run on initial setup). `watchEffect`, on the other hand, automatically tracks its reactive dependencies during its first execution. It re-runs whenever any of those tracked dependencies change, making it simpler for scenarios where you just need to react to whatever state is used inside the effect.