`triggerRef` does not trigger `watch(() => ref.value)`
Vue version
3.3.8
Minimal reproduction
This test fails:
import { nextTick } from 'vue'
test('triggerRef with watch', async () => {
const a = shallowRef(1)
let aTriggered = false
watch(() => a.value, () => {
aTriggered = true
})
triggerRef(a)
await nextTick()
expect(aTriggered).toBe(true)
})
What is expected?
Watching values of manually triggered references should execute the watch callback.
What is actually happening?
Watching the ref
itself works fine. According to post by @LinusBorg in https://github.com/vuejs/core/issues/1209#issuecomment-648953517, this is the expected design of Vue.
However, getting value
of the ref
does not work. So watch(() => a.value, ...)
won't work but, watch(a, ...)
work. The behavior should be the same and consistent for shallowRef
s where state tracking is disabled
watchEffect
works fine for these .value
calls. This is another undocumented inconsistency with watch
.
Official Vue docs state nothing about caching for watch
.
My linked comment is incorrect as it relates to triggerRef. I was, at that moment, more focused on the asynchronous execution of the test. Further down in the linked issue'S comments, Evan explains why the watch callback should not execute in these cases - because the callback should only run if the value actually changed, which is also documented as such, in my opinion.
(Sidenote: watchEffect
is different as it doesn't have a callback, it essentially is a watch with just the first argument - only the effect, not the callback. And the effect runs on any trigger, yes.)
The real inconsistency that I noticed is that the behaviour you desire is only happening if the first argument is a shallowRef:
const a = shallowRef(0)
watch(a, () => console.log('this will trigger'))
watch(() => a.value () => console.log(''this will not'))
Looking at the implementation of watch()
this could be by design? I have to call in @yyx990803 to get some insight in the desired behaviour.
I can presume this was done so that one can use watch()
when doing mutations to in non-reactive content in a shallowRef's value, but I personally think this behaviour is confusing, especially since it only works with the ref as the argument, not a getter reading the ref.
Though I could imagine that there's already userland code out there relying on this behavior, which we don't want to break, necessarily.
if we keep this behavior, we need to properly document it as a special behavior of watch()
with shallowRef()