My amount of components depends on array quantity, so when i add new item to array, it should create new component.
When new component is created i want to get reference on it, and that's where i have a misunderstanding. Last added component 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 component</button>
    <new-comp
        v-for="compId in arr"
        :ref="`components`"
        :index="compId"
        ></new-comp>
    </div>
  <script type="text/x-template " id="compTemplate">
    <h1> I am a component {{index}}</h1>
</script>
Vue.component("newComp",{
  template:"#compTemplate",
  props:['index']
})
new Vue({
  el:"#app",
  data:{
    arr:[1,2,3,4]
  },
  methods:{
    addNewComp:function(){
      let arr = this.arr;
      let components = this.$refs.components;
      arr.push(arr.length+1);
      console.log("sync",components.length);
      console.log("sync",components[components.length-1])
      setTimeout(() => {
        console.log("async",components.length);
        console.log("async",components[components.length-1])
      }, 1);
    }
  }
})
codepen link
refs, 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 components = this.$refs.components;
      arr.push(arr.length+1);
      console.log("sync",components.length);
      console.log("sync",components[components.length-1])
      Vue.nextTick(() => {                                         // changed here
        console.log("async",components.length);
        console.log("async",components[components.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 })
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