In Vue 3, watchers are used to trigger 'side effects' whenever reactive values/properties change. An example of these 'side effects' is mutating the DOM. This article will explain what the watch()
and watchEffect()
methods are and how you can use them in Vue 3 Composition API. You will need to be familiar with reactive variables (ref()
& reactive()
) in Vue 3 in order to understand fully how the watchers work. You can read this article if you are not familiar with ref()
& reactive()
.
watch()
The watch()
method runs lazily. What this means is that it does not run immediately the component is mounted, it only runs when it detects changes in the variables it is tracking. The method must be provided with the variable(s) it supposed to track.
It accepts 3 arguments: first is a getter function or the reactive variable or an array of variables/getter functions it is supposed to track (source), second is a callback function (called when the source changes) and last is an options object which influences the behaviour of the watch()
method.
Another thing to note with the method is that you are able to access both old and new values:
<script setup>
import { ref, watch } from "vue";
const count = ref(0);
watch(count, (newCount, oldCount) => {
console.log(`Count was ${oldCount}, now it is ${newCount}`);
});
</script>
Example of watching a reactive variable and a getter function at the same time:
<script setup>
import { ref, reactive, watch } from "vue";
const state = reactive({ count2: 0 });
const count = ref(0);
watch(
[() => state.count2, count],
([newCount2, newCount], [oldCount2, oldCount]) => {
console.log(`Count2 was ${oldCount2}, now it is ${newCount2}`);
console.log(`Count was ${oldCount}, now it is ${newCount}`);
}
);
</script>
Note, for the reactive object state
, we have used a getter funtion above. If we were to write the watcher like the code below, it would not work because the state.count2
would be passing a number to the watch()
and not the object property to be watched.
<script setup>
import { reactive, watch } from "vue";
const state = reactive({ count2: 0 });
// won't work
watch(state.count2, (count2) => {
console.log(`Count2 is ${count2}`);
});
// but this will work
watch(
() => state.count2,
(count2) => {
console.log(`Count2 is ${count2}`);
}
);
</script>
You can read more on the watch()
method, including the options object that can be passed to it in the Vue Documentation.
watchEffect()
The method runs once when the component mounts and then runs again when there is a change in the reactive variables. It also doesn't need a getter function, reactive variable or array of reactive variables/getter functions. It automatically watches all the reactive variables defined (reactive dependency watching).
watchEffect()
accepts 2 arguments, a callback function and last is an options object which influences the behaviour of the watchEffect()
method.
<script setup>
import { ref, watchEffect } from "vue";
const firstName = ref("John");
const lastName = ref("Doe");
watchEffect(() => {
console.log(`First name is ${firstName.value}`);
console.log(`Last name is ${lastName.value}`);
});
</script>
You can read more on the watchEffect()
method, including the options object that can be passed to it in the Vue Documentation.
The main difference between watch()
and watchEffect()
is that with watch()
, we can explicitly decide to track what we want to track and when the callback function should run. Dependency tracking is seperated from the side effects. With watchEffect()
, the reactive dependency tracking is done together with the side effects.
I hope this article has helped you understand the basics of both watch()
and watchEffect()
.