Reputation: 5982
I'm using a Vuex
store to keep all the items in a shopping cart.
There's two actions on the store :
getCartContent
, which gets called on page load (fetches the initial content from the backend, which in turn retrieves the data from the session)addToCart
, which is dispatched by the <Products>
component when the user clicks the add to cart button.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
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