I have a deep object in my pinia state that I want to put a watcher on.
export const useProductStore = defineStore("product", {
state: () => ({
attributes: {},
}),
});
When the object has data inside it can look like this:
attributes: {
english: {
0: {
key: "key1",
value: "value1"
},
1: {
key: "key2",
value: "value2"
},
...
}
}
I'm trying to put a watcher on this object but when the value changes the watch doesn't fire. Here's the component I'm trying to do this in:
<script setup>
import { useProductStore } from "@/stores/ProductStore";
import { storeToRefs } from "pinia";
const productStore = useProductStore();
const { attributes } = storeToRefs(productStore);
watch(() => ({...attributes}), (newValue, oldValue) => {
console.log(oldValue);
console.log(newValue);
}, { deep: true });
</script>
This comes straight from the pinia documentation, but when I change the state, nothing happens. Using vue dev tools I can see the state object being changed, so I know it is reactive. What am I missing?
storeToRefs
produces ref()
s.
You're saying the example "comes straight from the pinia documentation", but I doubt you found spreading a ref
anywhere in pinia docs. If you did, it's a mistake and should be pointed out to posva, by opening an issue on pinia
's repo.
A ref can be watched directly:
watch(
attributes,
handler,
{ deep: true }
)
...or you could watch its .value
with an arrow function 1:
watch(
() => attributes.value,
handler,
{ deep: true }
)
Note newVal
and oldVal
arguments are Proxies 2. To access their targets, use toRaw.
1 - it allows for narrower watchers, such as:
watch(
() => attributes.value[0]?.value),
handler
)
2 - if you place an object in a ref()
"the object is made deeply reactive with reactive()
" (see details). Also read Reactive Proxy vs Original.