Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why vue change specific array member not update dom

I want to know why I changed the specific item of an array and the page doesn't update. I know doc of vue.js points out that:

Due to limitations in JavaScript, Vue cannot detect the following changes to an array:

When you directly set an item with the index, e.g. vm.items[indexOfItem] = newValue.

It says we should do that, but I don't know why. And I've found a similar question(Vue computed issue - when will it compute again) about that.

Here is some code from the question above:

// works well

data() {
  return {
    cart: {
      item: {
        nums: 10,
        price: 10,
      },
    },
  }
},
computed: {
  total() {
    return this.cart.item.nums * this.cart.item.price
  },
},
methods: {
  set() {
    //why it worked.
    this.cart.item = {
      nums: 5,
      price: 5,
    }
  },
},

// oops! not working!

data() {
  return {
    cart: [
      {
        nums: 10,
        price: 10,
      },
    ],
  }
},
computed: {
  total() {
    return this.cart[0].nums * this.cart[0].price
  },
},
methods: {
  set() {
    this.cart[0] = {
      nums: 5,
      price: 5,
    }
  },
},

I'm confused about the answer from the question:

total will be recalculated if this.cart is marked as changed, this.cart[0] is marked as changed or if this.cart[0].nums or this.cart[0].price is changed. The problem is that you are replacing the object in this.cart[0]. This means that this.cart[0].price and nums do not change, because those still point to the old object.

If I have replaced the object in this.cart[0], why this.cart[0] isn't marked as changed? why this.cart[0].price and nums still point to old object? I have changed the this.cart[0]! right?

And why in the first situation it works well? also replace the object . What's the difference between the two scenarios?

like image 361
Archsx Avatar asked Aug 22 '19 18:08

Archsx


1 Answers

Vue is pretty explicit about this. It's a JavaScript limitation. JavaScript does not support the ability to detect when an array element changes, only when arrays change size as a result of adding or removing elements. Therefore replacing an element is not detectable.

What Vue does behind the scenes is sets up mechanics to watch for when objects change, which is something JavaScript does support. So array elements that are objects are things Vue can detect changes for. Since Vue cannot detect an array element being replaced, it doesn't know to stop looking at the old object and start looking at the new one.

The answer is also well-documented: if you want to update an item in an array, then use Vue.set(). This allows Vue to know that the array element is changing, so it knows to stop looking at the old object and start looking at the new one.

The solution therefore looks something like this:

Vue.set(this.cart, 0, {nums: 5, price: 5});
like image 136
B. Fleming Avatar answered Sep 28 '22 08:09

B. Fleming