I am working on a medium size web application based on vue.js. I've been facing several virtual DOM issues mostly related to vue instances life cycle.
The following code snippet (jsFiddle also available here) demonstrates some of these problems. The test-component vue component receives a property value and updates its internal state using that value.
Whenever the data set changes (by sorting or by new data), the properties are updated, but the internal state is not. This is pretty easy to see by running the code snippet and clicking on the buttons.
I understand the data component attribute is a function and it looks like it is invoked only when the component is created. That kind of explains what is going on. The thing is I don't know how to achieve the intended behavior which is: all the children components internal state to be updated whenever the data source changes.
Moving all the state to vuex would be a possible solution but some components are generic and I don't want them to contain knowledge about the vuex store details. Actually I am using vuex for most components, but for truly generic components I don't think it is a good option.
var testComponent = Vue.component('test-component', {
template: '#component_template',
props: ['prop1'],
data: function(){
return {
internalState: this.prop1
}
}
})
new Vue({
el: "#app",
data: function(){
return {
items: [
'Item 1',
'Item 2',
'Item 3'
],
dataToggle: true,
sorted: true
};
},
methods: {
sortDataSet: function(){
if(this.sorted){
this.items.reverse();
} else {
this.items.sort;
}
}
,changeDataSet: function(){
if(this.dataToggle){
this.items = ['Item 4', 'Item 5', 'Item 6', 'Item 7'];
} else {
this.items = ['Item 1', 'Item 2', 'Item 3'];
}
this.dataToggle = !this.dataToggle;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.2/vue.js"></script>
<body>
<h3>
Components internal state is not being updated
</h3>
<div id="app">
<button v-on:click="changeDataSet">
Change data
</button>
<button v-on:click="sortDataSet">
Sort data
</button>
<ul>
<li v-for="item in items">
<test-component :prop1="item">
</test-component>
</li>
</ul>
</div>
</body>
<script id="component_template" type="x-template">
<div>Prop: {{prop1}} || Internal state: {{internalState}}</div>
</script>
Use a key.
It is recommended to provide a key with v-for whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.
<li v-for="item in items" :key="item">
<test-component :prop1="item">
</test-component>
</li>
Updated fiddle.