Watch triggered even if value is not changed
Version
3.0.0
Reproduction link
https://jsfiddle.net/mravLjd6/4/
Steps to reproduce
Open console and watch output
What is expected?
Only one log message "true false"
What is actually happening?
Log fired every second with "false false"
const { computed, watch, ref } = Vue;
const source = ref(0);
const isZero = computed(() => source.value === 0);
watch(isZero, (prev, next) => console.log(prev, next)); // fires every second
setInterval(() => source.value++, 1000);
This is part from docs(https://v3.vuejs.org/guide/reactivity-computed-watchers.html#watch):
The watch API is the exact equivalent of the component watch property. watch requires watching a specific data source and applies side effects in a separate callback function. It also is lazy by default - i.e. the callback is only called when the watched source has changed.
I think this is intended as it allows to trigger a watcher whenever a computed is reevaluated. You can still only pay attention to the value by doing:
watch(() => isOdd.value, (prev, next) => console.log(prev, next));
It makes more sense to me that the watch is triggeret only two times, one with (true, true) and (true, false). Why is it implemented this way?. In other words, watch does not perform any comparation in the values?
The same behaviour with watchEffect
const { computed, watchEffect, ref } = Vue;
const source = ref(0);
const isZero = computed(() => source.value === 0);
watchEffect(() => console.log(isZero.value)); // fires every second
setInterval(() => source.value++, 1000);
with watchEffect() it's expected. Since computed properties are evaluated lazily(*), the effect has to run in order to determine whether or not the value of isZero
did change.
However for the watch(), we could check that the old & the new value are in fact different before calling the callback function.
- Lazy update: Whenever a dependency of a computed property changes, the computed property is marked as dirty but not evaluated straight away. It is only run when it is actually accessed
Here we basically assume that if it's a ref, the value definitely has changed and we can call the callback.
The issue is that a computed ref also counts as a ref, but it doesn't neccessarily have a changed value.
So I think we can simply remove the || isRefSource
condition here, that should fix it.