简体   繁体   中英

vue.js: v-for doesn't rerender content when array changed

Why v-for doesn't react to change some element in array?

this.test[3] = 3

If later I will call push for array, only then Vue rerender content.

this.test[3] = 3;
this.push(4);

Example: https://codepen.io/anon/pen/debJqK

 var vm = new Vue({ el: "#app", data: { test: [1, 2], }, methods: { changeVar1: function() { this.test[3] = 3; this.test.push(4); }, changeVar2: function() { this.test[3] = 3; } } })
 html * { box-sizing: border-box; } body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; padding: 4em; }
 <script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script> <div id="app"> <button @click="changeVar1()">Work</button> <button @click="changeVar2()">Doesn't work</button> <p v-for="(index, digit) in test">{{digit}}</p> </div>

If you add elements by index, you have to call Vue.set() :

Vue.set(this.test, 3, 3);

Or:

this.test.splice(3, 1, 3)

This enables Vue to adjust the reactivity to that element. Updated codePen .

Why?

Besides regular caveat problems, the docs have a specific guidance on arrays :

Caveats

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

  1. When you directly set an item with the index, eg vm.items[indexOfItem] = newValue
  2. When you modify the length of the array, eg vm.items.length = newLength

For example:

 var vm = new Vue({ data: { items: ['a', 'b', 'c'] } }) vm.items[1] = 'x' // is NOT reactive vm.items.length = 2 // is NOT reactive

To overcome caveat 1, both of the following will accomplish the same as vm.items[indexOfItem] = newValue , but will also trigger state updates in the reactivity system:

 // Vue.set Vue.set(vm.items, indexOfItem, newValue) // Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)

You can also use the vm.$set instance method, which is an alias for the global Vue.set :

 vm.$set(vm.items, indexOfItem, newValue)

To deal with caveat 2, you can use splice :

 vm.items.splice(newLength)

Updated stack snippet:

 var vm = new Vue({ el: "#app", data: { test: [1, 2], }, methods: { changeVar1: function() { this.test[3] = 3; this.test.push(4); }, changeVar2: function() { Vue.set(this.test, 3, 3); // this.test.splice(3, 1, 3); // would work the same } } })
 html * { box-sizing: border-box; } body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; padding: 4em; }
 <script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script> <div id="app"> <button @click="changeVar1()">Work</button> <button @click="changeVar2()">Didn't work, now fixed</button> <p v-for="(index, digit) in test">{{digit}}</p> </div>

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