Vue 3 watch doesn't work if I watch a destructured prop

I don’t understand why this is not working… What am I doing wrong?

P.S. I am using Vue 3 + Vite

export default {
    props: {
        modelValue: {
            type: Boolean,
            default: false,
        },
    },

    setup({ modelValue }, context)
    {
        watch(() => modelValue, (newValue, oldValue) => {
            console.log(newValue)
        })
    },
}

But if I don’t destructure it then it works

setup(props, context) {
    watch(() => props.modelValue, (newValue, oldValue) => {
        console.log(newValue)
    })
},

At its heart, reactivity is about reading and writing properties. Vue’s reactivity system doesn’t do any code analysis. It relies exclusively on recording which properties are read when.

A dependency is added when a property is read. But a dependency only makes sense if Vue knows what to do about it. What should it do when the property value changes?

In your first example, you are reading the value of the modelValue prop at the point the setup function is entered. All Vue knows is that you read the property value during setup. It doesn’t know what it’s supposed to do when the value changes, so no dependency can be added.

In the second example you are reading the property inside the watch function. When you call watch, Vue starts tracking before it invokes that first function. It knows what it’s supposed to do if the property value subsequently changes. So in that case it can add a dependency.

The problem with destructuring is documented here:

https://v3.vuejs.org/guide/composition-api-setup.html#props