1

I'm trying to apply some inline styles to the element in mounted hook for a short duration as a starting point for a transition.

  mounted() {
    this.styles = {
      backgroundColor: 'silver'
    };

After that, on the next tick, I want to add a set of new styles, and let the transition happen

    this.$nextTick(() => {
      this.styles = {
        backgroundColor: 'gold'
      }
    });
  }

This doesn't work as I expect it to, it renders the element with the second style right away.

If I replace the$nextTick with a setTimeout, it works as expected.

Where am I wrong? There must be a way to achieve this without relying on a timeout.

I've recreated the problem here

PS I know I could do this with Vue transitions, but in the actual project the styles to be applied are more complex & are programatically calculated, so I'd rather do it in js, than css

vch
  • 651
  • 5
  • 14
  • You have said that it works using `setTimeout`. In your example I can see you did wait 100 miliseconds in a timeout. `$nextTick` last shorter then that. I understand that this is not what you have expected to be but this is how it works. – Adam Orłowski Sep 05 '21 at 18:36
  • 1
    setTimeout(() => { this.styles = { backgroundColor: 'pink' } }, 0); You can do Timeout with 0 time for the effect you want. It should be the same as the nextTick, which doesn't work for some reason. – digitalniweb Sep 05 '21 at 18:41
  • As I have put in the answer, you need to wait for the next `event loop`. The `$nextTick` does not do that – Adam Orłowski Sep 05 '21 at 18:43

2 Answers2

2

You have said that it works using setTimeout. In your example I can see you did wait 100 miliseconds in a timeout. $nextTick last shorter then that. It does not wait for the next event loop.

I understand that this is not what you have expected to be but this is how it works. You need to wait for another event loop. Even using timeout with 0 will do the trick.

setTimeout(() => {
    this.styles = {
    backgroundColor: 'pink'
  }
}, 0);
Adam Orłowski
  • 4,268
  • 24
  • 33
  • 1
    Mhm. You're right, it does work with timeout `0`. I guess [docs](https://v3.vuejs.org/api/instance-methods.html#nexttick) are a little misleading, saying to `Use it immediately after you've changed some data to wait for the DOM update`. When actually (like [this](https://stackoverflow.com/a/47636157/16627614) answer clarifies) nextTick happens after Vue.js has updated the virtual DOM, but before the browser has rendered that change on the page. Now that explains the questioned behaviour – vch Sep 05 '21 at 19:11
0

In your case there is almost no delay between two renders. To see how silver will turn into gold you can call setTimeout:

    this.$nextTick(() => {
      setTimeout(() => {
      this.styles = {
        backgroundColor: 'gold'
      }
    }, 1000)
    });

I'm not sure you should use it as a ready-to-go solution because it's better to use CSS transitions. Maybe you just need to change not only styles but add some classes too to turn on CSS transitions when your style calculations are done.

Anatoly
  • 20,799
  • 3
  • 28
  • 42
  • Like I said in the question, sure, it works with the timeout, but it most definitely should work without it as well – vch Sep 05 '21 at 18:05