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 ifthis.cart[0].nums
orthis.cart[0].price
is changed. The problem is that you are replacing the object inthis.cart[0]
. This means thatthis.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?
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});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With