Drown
Drown

Reputation: 5982

Calling two mutations from the same action

I'm using a Vuex store to keep all the items in a shopping cart.

There's two actions on the store :

Both of these call a respective mutation (with the same name), since you're not supposed to call mutations directly from within components.

Here is what the store looks like :

const store = new Vuex.Store({
	state: {
		items: [],
	},

	mutations: {
		getCartContent(state, data){
			axios.get('/api/cart').then(response => {
				state.items = response.data;
			});
		},

		addToCart(state, data){
			axios.post('/api/cart/add', {
				item_id: data.item,
			});
		}
	},

	actions: {
		getCartContent(context){
			context.commit('getCartContent');
		},

		addToCart(context, data){
			context.commit('addToCart', {item: data.item});
		}
	}
});

This is working as expected, but now when an item is added to the cart (with a dispatch to the addToCart action from within the component), I would like it to call the getCartContent mutation just after so that it fetches a fresh list of items from the backend.

I tried commiting the second mutation from the same action, like this :

actions: {
    // ...
 
	addToCart(context, data){
		context.commit('addToCart', {item: data.item});
		context.commit('getCartContent');
	}
}

But that doesn't always work, sometimes it will fetch the items but not always.

I also tried dispatching the getCartContent action from within the component itself, right after dispatching the addToCart action, but it's the same problem.

How can I solve this?

Upvotes: 1

Views: 3450

Answers (1)

thanksd
thanksd

Reputation: 55644

Your axios calls are asynchronous, meaning that your addToCart mutation might not necessarily be finished when your getCartContent mutation fires. So, it's not surprising that sometimes getCartContent doesn't return the items you told axios to send a post request for immediately prior.

You should move asynchronous calls to the vuex actions:

actions: {
  getCartContent(context, data) {
    axios.get('/api/cart').then(response => {
      state.items = response.data;
      context.commit('getCartContent', response.data), 
    });
  },
  addToCart(context, data) {
    axios.post('/api/cart/add', {
      item_id: data.item,
    }).then(() => {
      context.commit('addToCart', data.item)
    })
  },
}

And your mutations should do nothing but make simple, straight-forward changes to the module state:

mutations: {
  getCartContent(state, items) {
    state.items = items;
  },
  addToCart(state, item) {
    state.items.push(item);
  }
}

The above explanation assumes that instead of making a get('/api/cart') request after each POST request, you would just keep track of items by pushing the data to the state.items property.

If however, you really want to make the GET request after adding an item, you can just get rid of the addToCart mutation and dispatch the getCartContent action after the POST request finishes:

addToCart(context, data) {
  axios.post('/api/cart/add', {
    item_id: data.item,
  }).then(() => {
    context.dispatch('getCartContent');
  })
},

Upvotes: 3

Related Questions