1
votes

How to instantaneously update changes committed to vuex store in the ui of another component?

following is the vuex store module of a component

const { property } = require("lodash")
export default {
  state: {
    data: [
        {id: 1, name: 'Angular', status: 'active'},
        {id: 2, name: 'React', status: 'active'},
        {id: 3, name: 'Vue', status: 'inactive'},
    ]
  },
  mutations: {
    UPDATE_ITEM(state, payload) {
        const item = state.data.find(item => _.isEqual(item, payload.item))

      Object.assign(item, payload.status);
    },
  },
  actions: {
    updateItem({ commit }, payload) {
      commit("UPDATE_ITEM", payload);
    },
  },
  getters: {
getData: (state) => state.data,
getMappedStatus: (state) => state.data.map(data => data.status)
  },
};

this is how I get mapped status in component 1

computed: {
    getMappedStatus() {
      return  this.$store.geters.getMappedStatus
    }
}

and inside the ui of component 1

<ul>
<li v-for="item in getMappedStatus>{{item}} </li>
</ul>

from another component 2 I'm updating the changes as the user inputs the status:

onStatusChanges(item, status) {
    this.$store.dispatch("updateItem", {
        item, status
    });
  },

But the problem is that even though the state is getting updated the ui is not getting updated.But (inside component 1)

I think it is because of the computed property. ... not sure.

How can I implement something like and observable or something reactive so that the getMappedStatus computed property in component 1 will get updated automatically as action is dispatched from component 2.

NOTE Both components come under the same vuex store module

If this was in angular/ngrx I would subscribe to the selectors inside the component 1 and I would get instantaneously the changes. even If I subscribe to the event inside the onInit() method or constructor() and do a console.log() the changes from the other component will be reflected instantaneously.

But this is not happening with vuex.

How can I achieve that:?

or is there a way to trigger the updation of the getMappedStatus computed property inside component 1 as soon as changes occurs from component 2:

computed: {
    getMappedStatus() {
      return  this.$store.geters.getMappedStatus
    }
}

so that the ui of component 1 updates instantaneously.

2
updateItem action returns a <promise>. Commit a mutation to vuex store in then block. and then use computed in what ever component you want. - Mohammad Basit
Yeah. But updateItem is an action dispatched from another component. But I need the changes to be reflected in a different component via the getters. - mx_code

2 Answers

1
votes

We can think of getters as computed properties for stores. Like computed properties, a getter's result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed so that simply means if component1 mutates the state in vuex store and component2 uses that property from the store it will automatically update in all components using it.

Online IDE - Live Demo Here

Vuex Store

const store = new Vuex.Store({
   state: {
     name: 'mex'
   },
   mutations: {
     mutateName(state, value) {
       state.name = value;
     }
   },
   actions: {
     updateName(context, payload) {
       context.commit('mutateName', payload.name);
     }
   },
   getters: {
     getName(state) {
       return state.name;
     }
   }
});

The changeName method when fired will dispatch updateName action which will update the name and all the components will update accordingly because it's reactive.

Then In Any Component

computed:{
  name() {
    return this.$store.getters.getName
  }
},
methods: {
  changeName: function () {
    this.$store.dispatch('updateName', {  name: 'mexxxxx'});
  }
}
0
votes

You need to return something from getMappedStatus

computed: {
    getMappedStatus() {
        return this.$store.geters.getMappedStatus
    }
}

...without a return statement the this.$store.geters.getMappedStatus is just an expression and your computed property always returns undefined (because JS functions without return always return undefined)