Search code examples
javascriptvue.jsvuejs3vue-composition-apipinia

Watching state object in pinia doesn't fire when object changes


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?


Solution

  • 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.

    Working demo.


    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.