Vue3 composition API watch store value
Asked Answered
A

3

17

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 the following 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() will not be called when myvalue is changed.

Arrhythmia answered 31/5, 2021 at 14:36 Comment(0)
M
27

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/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/[email protected]/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!

Mismate answered 31/5, 2021 at 15:50 Comment(2)
Is it recommended to write the computed in the return statement? asked in general.Jillianjillie
it's just a matter of preference if you have a "small-enough" setup function, it's likely fine. As the the complexity rises, it makes for better housekeeping. Functionally, there's no difference.Mismate
C
5

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();
}
Coast answered 3/4, 2022 at 10:1 Comment(0)
G
1

Using <script setup> in Vue 3 composition API. The solution would be like so:

Lets say you have the following getters in your store:

getters:{
  myValue(state){
    return state.myValue
  }
}

Script setup:

<script setup>
  import {watch} from 'vue'
  import {useStore} from 'vuex'

  const store = useStore()

  watch(() => store.getters.myValue, () => {
    console.log('value changes detected')
  })
</script>

Note: like @Daniel points out, to make it work, in watch() you need to pass a function (() => store.getters.myValue) that return myValue from the store getters. It can also be written like so:

watch(function(){return store.getters.myValue}, () => {
  console.log('value changes detected')
})
Galloping answered 13/10, 2022 at 10:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.