Reputation: 51
I'm building a shopping cart page using Vuejs and Vuex. Each item in the cart should have a quantity counter to increase or decrease number of pieces ordered for this specific item. When I add products to the cart from the main products page then visit the cart page. I click on the counter and the product quantity is changed but the UI doesn't show this change. It only shows the change after I reload the page and after that it can show any new changes to only this specific counter, and I have to reload after adding every product just to make its counter show UI changes.
This is the cart Vue component simplified:
<template >
<tbody>
<tr v-for="product in cartProducts" :key="product.name">
<td class="quantity">
<i class="fa fa-minus" @click="decreaseQuantity(product)"></i>
<p>{{product.quantity}}</p>
<i class="fa fa-plus" @click="increaseQuantity(product)"></i>
</td>
</tr>
</tbody>
</template>
<script>
export default {
computed: {
cartProducts() {
return this.$store.state.cartProducts;
},
},
methods: {
increaseQuantity(drug) {
const existedDrug = this.cartProducts.find(d => d.id === drug.id);
existedDrug.quantity += 1;
this.$store.dispatch("setUserDataCart", this.cartProducts);
console.log(this.$store.state.cartProducts);
},
decreaseQuantity(drug) {
const existedDrug = this.cartProducts.find(d => d.id === drug.id);
existedDrug.quantity -= 1;
this.$store.dispatch("setUserDataCart", this.cartProducts);
console.log(this.$store.state.cartProducts);
},
},
};
</script>
And this is my vuex store:
import Vue from "vue";
import Vuex from "vuex";
import VuexPersist from "vuex-persist";
Vue.use(Vuex);
const vuexPersist = new VuexPersist({
key: "my-app",
storage: window.localStorage
});
const store = new Vuex.Store({
state: {
cartProducts: []
},
mutations: {
SET_USER_CART(state, data) {
state.cartProducts = data;
}
},
actions: {
setUserDataCart({ commit }, data) {
commit("SET_USER_CART", data);
}
},
plugins: [vuexPersist.plugin]
});
export default store;
I tried multiple approaches like using mapState
or using the state as a getter
but no luck.
Can anyone identify what am I doing wrong?
Upvotes: 3
Views: 5740
Reputation: 766
In Vue.js docs:
Computed properties are by default getter-only
The way you did you're trying to change a computed property without a set method. What could be happening is that changing only the object property and not creating a new one might not be triggering the reaction to update the UI.
I would actually recommend to take another approach and move the logic to store's mutation method, passing only the id of the product you need to increment/decrement. And also use a method that returns a brand new object after the update (like map()
method I use to change cartProducts
.
store.js:
import Vue from "vue";
import Vuex from "vuex";
import VuexPersist from "vuex-persist";
Vue.use(Vuex);
const vuexPersist = new VuexPersist({
key: "my-app",
storage: window.localStorage
});
export default new Vuex.Store({
state: {
cartProducts: [
{
id: 1,
name: "Drug 1",
quantity: 1
},
{
id: 2,
name: "Drug 2",
quantity: 1
}
]
},
mutations: {
INCREMENT(state, productId) {
state.cartProducts = state.cartProducts.map(product => {
if (product.id === productId) {
product.quantity += 1;
}
return product;
});
},
DECREMENT(state, productId) {
state.cartProducts = state.cartProducts.map(product => {
if (product.id === productId) {
product.quantity -= 1;
}
return product;
});
}
},
actions: {
incrementQuantity({ commit }, productId) {
commit("INCREMENT", productId);
},
decrementQuantity({ commit }, productId) {
commit("DECREMENT", productId);
}
},
plugins: [vuexPersist.plugin]
});
cart.js
<template>
<table>
<tbody>
<tr v-for="product in cartProducts" :key="product.name">
<td class="quantity">
<button @click="decreaseQuantity(product)">decrease</button>
<p>{{ product.quantity || 0 }}</p>
<button @click="increaseQuantity(product)">increase</button>
</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
computed: {
cartProducts() {
return this.$store.state.cartProducts;
}
},
methods: {
increaseQuantity(drug) {
this.$store.dispatch("incrementQuantity", drug.id);
},
decreaseQuantity(drug) {
this.$store.dispatch("decrementQuantity", drug.id);
}
}
};
</script>
Upvotes: 2
Reputation: 56
Please read vuex documentation carefully. - https://vuex.vuejs.org/guide/ Changing the state should happened in the mutation methods. Here is an simple example from the Docs:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Upvotes: 0