Search code examples
vue.jsvuex

Vuex state change on object does not trigger rerender


I have a variable in the vuex store called permissions. And i want my component to trigger a rerender when the getPermissions changes. In the vue devtools i clearly see that the state has changed in the store, but the component stil get the old state from getPermissions. In order for me to see changes, I have to do a refresh. Has it something to do with the way i mutate it? or the fact that it is an object?

It looks like this when populated:

permissions: { 
    KS1KD933KD: true,
    KD9L22F732: false
}

I use this method to do mutations on it and a getter to get it:

const getters = {
  getPermissions: state => state.permissions
};

const mutations = {
  set_recording_permissions(state, data) {
    let newList = state.permissions;
    newList[data.key] = data.bool;
    Vue.set(state, 'permissions', newList);
  }
};

And in the component i use mapGetters to get access to it

computed: {
    ...mapGetters('agentInfo',['getPermissions'])
  }

In order to update the permissions value i use this action (it does require a succesfull api request before updating the value) :

const actions = {
  async setRecordingPermissions({ commit }, data) {
    let body = {
      agentId: data.userName,
      callId: data.callId,
      allowUseOfRecording: data.allowUseOfRecording
    };
    try {
      await AgentInfoAPI.editRecordingPermissions(body).then(() => {
        commit('set_recording_permissions', { key: data.callId, bool: data.allowUseOfRecording });
        commit('set_agent_info_message', {
          type: 'success',
          text: `Endret opptaksrettigheter`
        });
      });
    } catch (error) {
      console.log(error);
      commit('set_agent_info_message', {
        type: 'error',
        text: `Request to ${error.response.data.path} failed with ${error.response.status} ${error.response.data.message}`
      });
    }
  }
}

Solution

  • Since the getter only returns state variable you should use mapState, if you want to access it directly.

    computed: mapState(['permissions'])
    

    However, you can also use mapGetters, but then in your template, have to use getPermissions and not permissions. Example template:

    <ul id="permissions">
      <li v-for="permission in getPermissions">
        {{ permission }}
      </li>
    </ul> 
    

    If you have done this it is probably an issue with the object reference. You use Vue.set, but you set the same object reference. You have to create a new object or set the key you want to update directly.

    new object

    let newList = { ...state.permissions };
    

    Vue.set

    Vue.set(state.permission, data.key, data.value);