My amount of ponents depends on array quantity, so when i add new item to array, it should create new ponent.
When new ponent is created i want to get reference on it, and that's where i have a misunderstanding. Last added ponent is undefined
when i try to get it.
But, if i trying to get reference on it after some time, it work. I guess it's because of asynchronous, but i'm not sure.
Why this is happening and if there a way to avoid using setTimeout
?
<div id="app">
<button @click="addNewComp">add new ponent</button>
<new-p
v-for="pId in arr"
:ref="`ponents`"
:index="pId"
></new-p>
</div>
<script type="text/x-template " id="pTemplate">
<h1> I am a ponent {{index}}</h1>
</script>
Vueponent("newComp",{
template:"#pTemplate",
props:['index']
})
new Vue({
el:"#app",
data:{
arr:[1,2,3,4]
},
methods:{
addNewComp:function(){
let arr = this.arr;
let ponents = this.$refsponents;
arr.push(arr.length+1);
console.log("sync",ponents.length);
console.log("sync",ponents[ponents.length-1])
setTimeout(() => {
console.log("async",ponents.length);
console.log("async",ponents[ponents.length-1])
}, 1);
}
}
})
codepen link
My amount of ponents depends on array quantity, so when i add new item to array, it should create new ponent.
When new ponent is created i want to get reference on it, and that's where i have a misunderstanding. Last added ponent is undefined
when i try to get it.
But, if i trying to get reference on it after some time, it work. I guess it's because of asynchronous, but i'm not sure.
Why this is happening and if there a way to avoid using setTimeout
?
<div id="app">
<button @click="addNewComp">add new ponent</button>
<new-p
v-for="pId in arr"
:ref="`ponents`"
:index="pId"
></new-p>
</div>
<script type="text/x-template " id="pTemplate">
<h1> I am a ponent {{index}}</h1>
</script>
Vue.ponent("newComp",{
template:"#pTemplate",
props:['index']
})
new Vue({
el:"#app",
data:{
arr:[1,2,3,4]
},
methods:{
addNewComp:function(){
let arr = this.arr;
let ponents = this.$refs.ponents;
arr.push(arr.length+1);
console.log("sync",ponents.length);
console.log("sync",ponents[ponents.length-1])
setTimeout(() => {
console.log("async",ponents.length);
console.log("async",ponents[ponents.length-1])
}, 1);
}
}
})
codepen link
Share Improve this question asked Apr 26, 2018 at 9:55 Nazar KotsyubaNazar Kotsyuba 1771 gold badge1 silver badge12 bronze badges 2-
I am unsure what your problem is, but maybe you're looking for the
updated
lifecycle? – A. L Commented Apr 26, 2018 at 10:19 - @A.Lau yes, that helped, thank you – Nazar Kotsyuba Commented Apr 26, 2018 at 11:01
1 Answer
Reset to default 12ref
s, and $refs
, are not reactive.
If you want to pick up the updated value, you should wait until the next render cycle updates the DOM.
Instead of setTimeout
you should use Vue.nextTick()
:
new Vue({
el:"#app",
data:{
arr:[1,2,3,4]
},
methods:{
addNewComp:function(){
let arr = this.arr;
let ponents = this.$refs.ponents;
arr.push(arr.length+1);
console.log("sync",ponents.length);
console.log("sync",ponents[ponents.length-1])
Vue.nextTick(() => { // changed here
console.log("async",ponents.length);
console.log("async",ponents[ponents.length-1])
}); // changed here
}
}
})
And this is not a "hack", this is the proper way of doing it. From the official API docs:
Vue.nextTick( [callback, context] )
Arguments:
{Function} [callback]
{Object} [context]
Usage:
Defer the callback to be executed after the next DOM update cycle. Use it immediately after you've changed some data to wait for the DOM update.
// modify data vm.msg = 'Hello' // DOM not updated yet Vue.nextTick(function () { // DOM updated }) // usage as a promise (2.1.0+, see note below) Vue.nextTick() .then(function () { // DOM updated })