Dan Knights
Dan Knights

Reputation: 8378

Update DOM on Vuex store state change

I have an 'Add To Basket' button which triggers a Vuex store action:

<button
  @click="addToBasket(item)"
>
  Add To Basket
</button>

Vuex store:

const actions = {
    addToBasket({ commit }, item) {
        commit("setBasketItems", item);
    }
};

const mutations = {
    setBasketItems: (state, item) => {
        let basketFind = state.basket.find(i => {
            return i.id === item.id;
        });

        if (basketFind) {
            basketFind.quantity += 1;
            return;
        }

        item.quantity = 1;

        state.basket.push(item);
    }
};

const state = {
    basket: []
};

const getters = {
    basketItems: state => state.basket,
};

When I check the Vuex store in dev tools it's doing what it should, i.e adding the item if it doesn't exist, incrementing the quantity if it does.

I'm trying to update the DOM to display the item's quantity:

computed: {
  computedBasketItems: function() {
    return this.$store.getters.basketItems;
  }
},
<CartItem
  v-for="item in computedBasketItems"
  :key="item.id"
  :item="item"
/>

CartItem (accepting the item as a prop):

<div class="dropdown-item">
  <i class="fa fa-times-circle"></i>
  <router-link to="">{{ item.name }}</router-link>
  <p>{{ item.quantity }}x</p>
  <p>{{ item.price }}</p>
</div>

// props...
    props: ["item"],

It adds the item to the DOM and sets the quantity to '1' but doesn't update the quantity whenever it changes.

How can I do this?

Upvotes: 1

Views: 963

Answers (2)

user13198697
user13198697

Reputation:

  const mutations = {
    setBasketItems: (state, item) => {
      // in this line we checking if item id equal state backet item id it returns first matched element 
      let basketFind = state.basket.find((i) => {
        return i.id === item.id;
      });

      // here we checking if basketFind has value(aka array contains value) 
      if (basketFind) {

        // if basketFind is true in this case will be implement this block
        state.basket = state.basket.map((x) =>
          x.id === item.id ? { ...x, quantity: x.quantity + 1 } : x
        );

        // in this line we reassigning basket prop of state with transformed data
        // just checking if  x.id === item.id then increase matched element's prop quantity  
        // also we leave other elements which contains state.basket array
        return;

      }
      // if basketFind is false we going this line
      // again, reassigning basket prop of state. adding existing element and adding new element with value 1 of quantity prop
      state.basket = [
        ...state.basket,
        ...[item].map((x) => ({ ...x, quantity: 1 })),
      ];
    },
  };

Upvotes: 1

Prabhat Gupta
Prabhat Gupta

Reputation: 137

The reason is that your items you are adding are not reactive. only your basket array is reactive. and adding Item to It will re-render. but you are just pushing the Item, and if you change the Item's property its not reactive. to do that use Vue.$set(basketFind,'quantity',basketFind.quantity+1) in place of basketFind.quantity += 1;

Upvotes: 0

Related Questions