Watch Vuex Store State Change in a Vue.js App

John Au-Yeung - Jan 26 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

We can easily watch for store Vuex store changes in a Vue.js app by adding computed properties or using getters.

In this article, we'll look at how to do watch the Vuex store state with both ways.

Computed Properties

We can use computed properties to watch for the latest value from the store and return it.

For instance, we can write the following code to create a store and then access the value in a component:

main.js:

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";
Vue.use(Vuex);

Vue.config.productionTip = false;

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment(state) {
      state.count++;
    }
  }
});

new Vue({
  store,
  render: h => h(App)
}).$mount("#app");
Enter fullscreen mode Exit fullscreen mode

App.vue:

<template>
  <div id="app">
    <button @click="increment">Increment</button>
    <p>{{count}}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  computed: {
    count() {
      return this.$store.state.count;
    }
  },
  methods: {
    increment() {
      this.$store.commit("increment");
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the the store in main.js which holds the count state.

We put the store in our Vue instance. Then in App.vue, we reference the store by using this.$store.

Then we can access the count state we did in the count method in the computed property.

In the end, we see the latest count displayed on the screen as we click the Increment button to call increment, which commits a new value to the store.

Getters

We can create a getter in the store and then use the mapGetters method to add the getter as a computed property in our component. For instance, we an write the following to do that:

main.js:

import Vue from "vue";
import App from "./App.vue";
import Vuex from "vuex";
Vue.use(Vuex);

Vue.config.productionTip = false;

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

new Vue({
  store,
  render: h => h(App)
}).$mount("#app");

Enter fullscreen mode Exit fullscreen mode

App.vue:

<template>
  <div id="app">
    <button @click="increment">Increment</button>
    <p>{{count}}</p>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  name: "App",
  computed: {
    ...mapGetters(["count"])
  },
  methods: {
    increment() {
      this.$store.commit("increment");
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

In the code above, we added a getter in our store with:

getters: {
  count: state => {
    return state.count;
  }
}
Enter fullscreen mode Exit fullscreen mode

in main.js. Then in the script section of App.vue, we have:

import { mapGetters } from "vuex";
export default {
  name: "App",
  computed: {
    ...mapGetters(["count"])
  },
  methods: {
    increment() {
      this.$store.commit("increment");
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

We imported the mapGetters method from vuex to add the getter directly as a computed property.

In the array we passed into mapGetters we pass in the getter name from the store to access the returned value from the getter.

Therefore, we'll see the same result as before.

Conclusion

Computed properties are good for getting some simple states. If we need to derive states from a given state, then we should use getters with the mapGetters method to map them to computed properties.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .