appu
appu

Reputation: 481

VueX: why vuex store data does not update components data property?

In the following code, components (app.vue) c2 property does not get updated when increment updates stores counter this.$store.state.counter++;

I know I can solve this by using c2 as computed property but I would like to know why Vuex or vue does not initiate reactivity since the counter's value was updated by increment method.

Store.js

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export const store = new Vuex.Store({
  state: {
    counter: 0
  },
  mutation: {
    increment() {
      return this.$state.counter++;
    }
  }
});

App.vue

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

<script>
export default {
  data() {
    return {
      c2: this.$store.state.counter
    };
  },
  methods: {
    increment() {
      this.$store.state.counter++;
    }
  }
};
</script>

Thanks

Upvotes: 0

Views: 1447

Answers (1)

enbermudas
enbermudas

Reputation: 1615

Vuex uses something called "actions" and they look just like mutations, but instead of mutating the state, they commit mutations. You can't modify your Vuex store state like this:

methods: {
  increment() {
    this.$store.state.counter++
  }
}

Instead, you should create a actions object inside your store with an action:

actions: {
  increment (context) {
    context.commit('increment')
  }
}

Now, that code says this: "whenever you dispatch me (action), run the code inside the mutation called increment" which means: "commit the mutation called increment".

Another important thing is your component method called "increment". You should modify it to look like this:

methods: {
  increment() {
    this.$store.dispatch('increment')
  }
}

Now, whenever you call this method you will dispatch an action that will commit a mutation.

Finally, in order to get your state inside your component (the good way at least) would be using the mapState function that Vuex provides.

First, import this inside your component script tag:

import { mapState } from 'vuex'

And create a computed property like this:

computed: mapState([
  'counter'
])

This will give you access to the counter property that was define inside your store state. In that case, you can delete the return statement in your data() function and change your html in order to display the counter property:

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

And that would be it!

Upvotes: 1

Related Questions