7

I'm trying to figure out how to properly update a getter value when some other variable from VueX changes/updates. Currently I'm using this way in a component to update:

watch: {
   dates () {
     this.$set(this.linedata[0].chartOptions.xAxis,"categories",this.dates)
   }
}

So my getter linedata should be updated with dates value whenever dates changes. dates is state variable from VueX store. The thing is with this method the value won't be properly updated when I changed route/go to different components. So I think it's better to do this kind of thing using the VueX store.

dates is updated with an API call, so I use an action to update it. So the question is how can I do such an update from the VueX store?

EDIT:

I tried moving this to VueX:

async loadData({ commit }) {
      let response = await Api().get("/cpu");
      commit("SET_DATA", {
       this.linedata[0].chartOptions.xAxis,"categories": response.data.dates1,
this.linedata[1].chartOptions.xAxis,"categories": response.data.dates2
      });
    }

 SET_DATA(state, payload) {
      state = Object.assign(state, payload);
    }

But the above does not work, as I cannot set nested object in action this way...

3
  • Getters are generally for getting, not setting. They are like computed for Vuex, which return calculated data. They update automatically when reactive contents change. So it's probably best to rethink the design so that only state needs to be updated. Either way, Vuex should be updated only with actions/mutations. Commented Mar 11, 2020 at 13:58
  • Hmm okay lets say this linedata is then state value. How should I change it? I tired setting that in action I get error when i try to do this: commit("SET_DATA", {linedata[0].chartoptions.xAxis["categories"]: response.data.dates}) Commented Mar 11, 2020 at 14:02
  • 1
    No worries, your answer ans explanation in the chat helped me understand much better what happens with data in Vuex store. Commented Mar 22, 2020 at 19:09

2 Answers 2

8
+50

Getters are generally for getting, not setting. They are like computed for Vuex, which return calculated data. They update automatically when reactive contents change. So it's probably best to rethink the design so that only state needs to be updated. Either way, Vuex should be updated only with actions/mutations

Given your example and the info from all your comments, using linedata as state, your action and mutation would look something like this:

actions: {
  async loadData({ commit }) {
    let response = await Api().get("/cpu");
    commit('SET_DATA', response.data.dates);
  }
}
mutations: {
  SET_DATA(state, dates) {
    Vue.set(state.linedata[0].chartOptions.xAxis, 'categories', dates[0]);
    Vue.set(state.linedata[1].chartOptions.xAxis, 'categories', dates[1]);
  }
}

Which you could call, in the component for example, like:

this.$store.dispatch('loadData');

Using Vue.set is necessary for change detection in this case and requires the following import:

import Vue from 'vue';

Theoretically, there should be a better way to design your backend API so that you can just set state.linedata = payload in the mutation, but this will work with what you have.

Sign up to request clarification or add additional context in comments.

6 Comments

Would this work with Object.assign? For example when in action I would want to set multiple values in state at once? But for some reason Vue does not allow me to set nested objects like the one above.
It's probably because you need Vue.set, which is necessary for change detection when setting array/object items. I edited my answer.
Let me give an example what I mean. In actions I'm trying to set several values like state.linedata[0]: setData({ commit} ) { commit('SET_DATA', {linedata[0].chartoptions.xAxis: response.data.dates1, linedata[1].chartoptions.xAxis:response.data.dates2}); } and then in mutation: ` SET_DATA(state, payload) { state = Object.assign(state, payload); },`
This worked perfectly for me, thanks. By the way is it good practice to use getters or other state values as a payload? In example above this would mean: commit('SET_DATA', { id: 0, data: SOMEGETTERHERE/STATEVARIABLE });
|
0

Here is a simple example of a Vuex store for an user.

export const state = () => ({
  user: {}
})

export const mutations = {
  set(state, user) {
    state.user = user
  },
  unset(state) {
    state.user = {}
  },
  patch(state, user) {
    state.user = Object.assign({}, state.user, user)
  }
}

export const actions = {
  async set({ commit }) {
      // TODO: Get user... 
      commit('set', user)
  },
  unset({ commit }) {
    commit('unset')
  },
  patch({ commit }, user) {
    commit('patch', user)
  }
}

export const getters = {
  get(state) {
    return state.user
  }
}

If you want to set the user data, you can call await this.$store.dispatch('user/set') in any Vue instance. For patching the data you could call this.$store.dispatch('user/patch', newUserData).

The getter is then reactively updated in any Vue instance where it is mapped. You should use the function mapGetters from Vuex in the computed properties. Here is an example.

...
computed: {
  ...mapGetters({
    user: 'user/get'
  })
}
...

The three dots ... before the function call is destructuring assignment, which will map all the properties that will the function return in an object to computed properties. Those will then be reactively updated whenever you call dispatch on the user store. Take a look at Vuex documentation for a more in depth explanation.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.