How to get Vue to update the actual DOM right away when nextTick doesn't work, from a .vue file?

vue force update computed
vue-component not updating on prop change
vue nexttick
vue forceupdate example
vue watch
vue reload child component
vue watch immediate
vue extends

When I have a Vue component in a .vue file with a data member isLoading: false, and a template:

<div v-show="isLoading" id="hey" ref="hey">Loading...</div>
<button @click="loadIt()">Load it</button>

And a method:

loadIt() {
  this.isLoading = true
  this.$nextTick(() => {
    console.log(this.$refs.hey)                  // virtual DOM
    console.log(document.getElementById('hey'))  // actual DOM
    // ...other work here
  })
}

I thought that the nextTick function would allow both the virtual and real DOM to update, and thus the two console.log lines would output the same results. However, they do not: it seems that the real DOM isn't being updated right away, and thus the second log results in a element with display: none; whereas the first log doesn't--I get this on the console:

<div id="hey" data-v-964d645e="" style="">
<div id="hey" data-v-964d645e="" style="display: none;">

(By the way, even if I use setTimeout instead of this.$nextTick, I get the very same results from console.log. I also tried using the updated hook, but the same symptoms happen there. If I code any variation in a .js file, the problem goes away, but it persists when in a .vue file.)

Is there some kind of optimization or further asynchrony in how Vue updates the actual DOM from the virtual DOM? How do I get the actual DOM to update right away?

Please review Vue lifecycle in the documentation. Of note is that there is a disconnect between these two events. Also note that nextTick() waits for the next DOM update cycle, not necessarily the virtual DOM.

This is typically addressed by using the updated lifecycle hook, which executes code after the virtual DOM has already been updated. If you need to execute some code with the guarantee that the virtual DOM has already been updated, you will want to do it there.

You may also be interested in reactivity in depth. This should act as a good complement to the lifecycle diagram.

The correct way to force Vue to re-render a component, monitors all data() members (it does this all the time, not only during 1st render). Sometimes Vue's reactivity system isn't enough, and you just need to re-render a component. Or maybe you just want to blow away the current DOM and start over. So how do you get Vue to re-render a component the right way? The best way to force Vue to re-render a component is to set a :key on the component. When you need the component to be re-rendered, you just change the value of the key and Vue will re-render the component.

This works pretty much as expected, with messages matching both before and after DOM update.

I think your understanding that the refs call returns a virtual node rather than an actual DOM element is incorrect.

new Vue({
  el: '#app',
  data: {
    isLoading: false
  },
  methods: {
    loadIt() {
      this.isLoading = true;
      this.tellMeAboutIt('before');
      this.$nextTick(() => this.tellMeAboutIt('after'));
    },
    tellMeAboutIt(when) {
        console.log(`Virtual ${when}:`, this.$refs.hey) // virtual DOM
        console.log(`Actual ${when}:`, document.getElementById('hey')) // actual DOM
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div v-show="isLoading" id="hey" ref="hey">Loading...</div>
  <button @click="loadIt()">Load it</button>
</div>

Do we have router.reload in vue-router?, When I have a Vue component in a .vue file with a data member isLoading: f I thought that the $nextTick function would allow both the virtual and actual DOM to update. Right now, I consider this "doubleRaf" a Vue. Sometimes when i'm updating large parts of the DOM, Vue.nextTick is not enough. In this cases, Justineo's solution with "double" requestAnimationFrame works most of the time. Right now, I consider this "doubleRaf" a Vue.nextTick with asteroids. Thanks @Justineo

Turns out that problems with either the eslint-loader cache or the babel-loader cache caused this weirdness. I could only fix it by deleting all of node_modules\.cache. Too bad I don't know why it happened in the first place.

Are methods in Vue reactive?, Or maybe you just want to blow away the current DOM and start over. So how do you get Vue to re-render a component the right way? If we don't wait until the next tick, our updates to renderComponent will just cancel and we think that Vue will react to changes to a certain property or variable, but it doesn't actually. Vue won’t re-render the component (and thus the DOM) automatically. It’ll queue up the required modification. Then, in the next “tick” (as in a clock), the queue is flushed, and the update is applied.

What is nextTick or what does it do in VueJs, This is an ES5-only and un-shimmable feature, which is why Vue doesn't present in the data object in order for Vue to convert it and make it reactive. For example: var vm = new Vue({ data: { a: 1 } }) // `vm.a` is now reactive vm.b = 2 // `​vm.b` is In case you haven't noticed yet, Vue performs DOM updates asynchronously. There is a handy method available on the global Vue object named nextTick. This method takes a callback as its argument, which is invoked the next time Vue has updated the DOM. This method takes a callback as its argument, which is invoked the next time Vue has updated the DOM.

How to wait for a browser re-render? Vue.nextTick doesn't seem to , But if I try the DOM query in the console after the page loads I get refs are only populated after the render is complete, so it doesn't help So right now, there are no “rows” to select or manipulate in the DOM. on the next tick, thereby ensuring th DOM has been updated after the data has been loaded. The extra ms in the setTimeout gives the DOM update routine just enough time to be invoked before the blocking loop is called. Unfortunately, we can't fine tune Vue.$nextTick to wait just that ms moment, so setTimeout (cb, 1) is out best bet. Hopes this helps someone jason90929 commented on Dec 11, 2018

Reactivity in Depth, You've seen a couple of times now that if you specify a function as the and then the actual hook is called afterward. Next hook doesn't guarantee that the element has been added to the DOM. To make sure that it has been added, you can call Vue. Maybe our data updates, though, so the DOM is updated to reflect that  In general, a Virtual Dom is just simply a JavaScript object which represents the Document Object Model(DOM). Your application will update the Virtual DOM and never actually has to update the DOM

Comments
  • Note that console can update the display after the fact (usually see an info icon). To be precise, you should save the state of this.$refs.hey.getAttribute("style") for an accurate snapshot. Does not negate your issue, though.
  • I can't reproduce on Codesandbox. Are you able to alter it to reproduce?
  • this.$refs.hey is not a virtual DOM element; it's an actual DOM element
  • I think all of you are right. Thanks for helping me find the problem. My follow-up is here: stackoverflow.com/questions/53707415
  • My mistake. It seemed like you were trying to perform DOM modifications. I'll revise my answer accordingly.
  • @PatrickSzalapski Please review my updated answer. Sorry for the incorrect assumption!
  • Great, thanks. That document reads, "In order to wait until Vue.js has finished updating the DOM after a data change, you can use Vue.nextTick(callback) immediately after the data is changed. The callback will be called after the DOM has been updated." Are you saying that part is incorrect?
  • Also, the updated documentation has this: "Note that updated does not guarantee that all child components have also been re-rendered. If you want to wait until the entire view has been re-rendered, you can use vm.$nextTick inside of updated." Does this contradict what you are saying? I'll try it.
  • The problem with nextTick() is that this will only work for one level of ancestry in your components. If your child components also have child components and you need to wait for these grandchild components to update, then nextTick() will be insufficient. If you need to await a full component ancestry re-render, you're going to run into some trouble. You should either better separate your components to decouple their functionality, or consider using inter-component communication (e.g. emit(event_name) and v-on:event_name).
  • I'm finding the strange behavior only when it is in a .vue file, but not when in a pure .js setting. Any ideas?
  • I've confirmed that the two different calls still return different results, even if called again: console.log(this.$refs.hey, document.getElementById('hey')); console.log(this.$refs.hey, document.getElementById('hey')) returns the elements with different styles, twice.
  • Interesting. On non-.vue file, the results are the same object; obviously not true for .vue files. Try this.$forceUpdate() after you set isLoading to see if you get the result you want.
  • $forceUpdate didn't help; behavior is the same.
  • Thanks for helping me find the problem. My follow-up is here: stackoverflow.com/questions/53707415