This is my sample:
// App.vue
<script setup lang="ts">
import { onMounted } from 'vue';
import { storeToRefs } from 'pinia';
import { useStore } from './store.js'
const store = useStore();
const { foo } = storeToRefs(store)
onMounted(() => {
console.log('nvmnghia mounted')
setTimeout(() => foo.value.bar++, 1234)
})
</script>
<template>
<div></div>
</template>
// store.js
import { ref, watch } from 'vue'
import { defineStore } from 'pinia'
export const useStore = defineStore('store', () => {
const foo = ref({ bar: 1 })
watch(foo, foo => console.log({ foo }), { deep: true })
return { foo }
})
If I remove { deep: true }, the watch log isn't printed. Vue docs said watchers are deep by default (their word: "implicit"):
When you call watch() directly on a reactive object, it will implicitly create a deep watcher - the callback will be triggered on all nested mutations: [code example]
Why do I still have to specify it?
Furthermore, if I still don't want to set deep, I have to do a React-like modification:
foo.value = { bar: foo.value.bar + 1 }
Pinia docs said storeToRefs() is enough to get reactive, but it doesn't apply here.
Yes, Vue docs said watchers are deep by default, but that's for reactive not ref.In Vue Source code,reactive is implemented by Proxy so its deeply reactive, and ref is implemented by getter and getter like vue2 so its not deeply reactive.In addition,when ref is using to an object like your code,In fact it seems like do this: const foo = ref(reactive({ bar: 1 })), so the foo.value is deeply reactive,and you can test it :watch(foo.value, foo => console.log({ foo }))