Vue3 composition api watch store value

Viewed 11675

I want to detect changes in a vuex state value by watching it in a Vue Component. I am currently using vue 3 with the composition api. I've tried this approach:

setup(props) {
   const store = useStore();

   watch(store.getters.myvalue, function() {
      console.log('value changes detected');
   });

   return {
      myvalue: computed(() => store.getters.myvalue)
   }
},

But the console log statement will not be called when myvalue is changed.

2 Answers

I think you might need to pass a function that returns myValue getter instead of passing the myValue getter.

like so:

setup(props) {
   const store = useStore();

   watch(()=>store.getters.myvalue, function() {
      console.log('value changes detected');
   });

   return {
      myvalue: computed(() => store.getters.myvalue)
   }
},

Here is a working example:

const store = Vuex.createStore({
  state() {
    return {
      count: 0
    }
  },
  getters: {
    count(state) {
      return state.count
    }
  },
  mutations: {
    increment(state) {
      state.count++
    }
  }
});

const app = Vue.createApp({
  setup() {
    const store = Vuex.useStore();

    Vue.watch(() => store.getters.count, function() {
      console.log('value changes detected');
    });

    store.watch((state, getters) => getters.count, () => {
      console.log('value changes detected via vuex watch');
    })

    return {
      myvalue: Vue.computed(() => store.getters.count),
      change: ()=>{store.commit('increment')}
    }
  }
});

app.use(store);

app.mount("#app");
<script src="https://unpkg.com/vue@3.0.3/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/vuex@4.0.0/dist/vuex.global.js"></script>

<div id="app">
  <button @click="change"></button>
  {{myvalue}}
</div>

However there are more Vuex-specific ways to do this such as using Vuex watch (or subscribe). Link for examples and more details: Watch for Vuex State changes!

Let me answer your question in general way.

First of all you need to create store with state, getters, actions and mutations.

Composition API

You need to import store inside the component via

import { useStore } from 'vuex';

And initialise it inside component like this:

export default {
 setup(){
  const store = useStore();
 }
}

In order to watch the store changes you can use watchEffect(), do not forget to import it

import { watchEffect } from '@vue/runtime-core';

watchEffect(() => {
  // pretend you have a getData getter in store
  const data = store.getters.getData;
  if(data === null) return;
  console.log(data);
})

Moreover, you can use watch(), which is a bit older way

import { watch } from '@vue/runtime-core';

watch(
  // pretend you have a getData getter in store
  () => store.getters.getData,
  (val, oldVal) => console.dir({ val, oldVal})
)

In some cases you will have a warnings in console like this

Invalid watch source:  null A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types. 

`watch(fn, options?)` signature has been moved to a separate API. Use `watchEffect(fn, options?)` instead. `watch` now only supports `watch(source, cb, options?) signature. 

Option API

Classic way to watch store changes is to create a function like this

data(){
 return {
  todo: null
 }
},
methods: {
 watchStore(){
  this.$store.watch(
    () => this.$store.getters.getData,
    data => this.todo = data
  )
 }
},
mounted(){
 this.watchStore();
}
Related