6
votes

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...

2
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. - Dan
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}) - Alex T
Oh wow, thank you for the bounty! Very generous. - Dan
No worries, your answer ans explanation in the chat helped me understand much better what happens with data in Vuex store. - Alex T

2 Answers

6
votes

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.

0
votes

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.