0
votes

I am passing the array drinks as props to Drinks.vue and map elements inside of Drinks.vue When I click the button, it is supposed to emit the event to change the element to 'Sold Out'. However, when debugging using console.log or Vue developer tool, it shows the drinks array is updated, but the page itself doesn't re-render or update... Fruits works well. Do you know why Drinks.vue could not update drinks array?

App.vue

<template>
  <div>
    <Header :shop_name="shop_name" v-on:change_shop_name_event="change_shop_name($event)" />
    <Fruits :stocks="fruits" v-on:sell_fruit_event="update_fruit_status($event)" />
    <Drinks :stocks="drinks" v-on:sell_drink_event="update_drink_status($event)" />

    <Footer :shop_name="shop_name" />
  </div>
</template>

<script>
import Header from "./components/Header.vue";
import Fruits from "./components/Fruits.vue";
import Drinks from "./components/Drinks.vue";
import Footer from "./components/Footer.vue";

export default {
  name: "App",
  components: {
    Header,
    Fruits,
    Drinks,
    Footer,
  },

  data: function () {
    return {
      shop_name: "Zowie Grocery",
      fruits: {
        Peach: 10,
        Apple: 10,
        Blueberry: 10,
        Strawberry: 10,
        Mongo: 10,
        Watermelon: 10,
      },
      drinks: ["beer", "orange juice", "milk shake", "tea", "coke"],
    };
  },

  methods: {
    change_shop_name: function (payload) {
      this.shop_name = payload;
    },

    update_fruit_status: function (payload) {
      this.fruits[payload] -= 1;
    },

    update_drink_status: function (index) {
      console.log(index);
      this.drinks[index] = "Sold Out";
    },
  },
};
</script>

<style>
</style>

Drinks.vue

<template>
  <div>
    <h2>This is the drinks we have in stock</h2>
    <div v-for="(value,index) in stocks" :key="index">
      <p>{{value}}</p>
      <button @click="sell(index)">Sell</button>
    </div>
  </div>
</template>


<script>
export default {
  name: "Drinks",
  props: ["stocks"],
  methods: {
    sell: function (index) {
      this.$emit("sell_drink_event", index);
    },
  },
};
</script>
2

2 Answers

0
votes

can you try this instead of this.drinks[index] = "Sold Out" :

this.drinks = this.drinks.map((k,idx)=> idx === index ? 'Sold Out' : k)
0
votes

Arrays are not reactive the way objects are in Vue.js. While just assigning a new value to an objects attribute just like that

someObject.x = 'some value'

it's not the same for an array and its elements. Just to clarify - yes, you can modify any index of an array but this won't trigger a re-render in Vue.js because of its reactivity system. If you modify an array by its index you've to take care about re-rendering the component yourself.

However, there's still hope. If you want Vue.js's reactivity system to take care about re-renders (even for Arrays) you've to use Vue.$set as stated in the docs.

So for your example it should be like this.

this.$set(this.drinks, index, 'Sold Out');

This will not only update the array but also toggle your expected re-render.