简体   繁体   中英

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, ie 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?

  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 })),
      ];
    },
  };

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM