简体   繁体   中英

VueJS doesn't re-render until loop is finished

I have this piece of VueJS code:

new Vue({
  el: '#app',
  data: {
    tiles: [
      { isActive: false },
      { isActive: false },
      { isActive: false },
      { isActive: false },
      { isActive: false }
    ]

  },
  methods: {
    startWithLoop: function() {
      console.log("startWithLoop");
      for(var i = 0; i < 10000; i++ ) { this.blink() };
    },
    startWithInterval: function() {
      console.log("startWithInteral");
      setInterval(this.blink);
    },
    blink: function(){
      console.log("blink");
      var index = Math.floor(Math.random() * this.tiles.length);
      this.tiles[index].isActive = !this.tiles[index].isActive;
    }
  }
})

If I call the method startWithInterval I can see in the view how the tiles are changing state all the time.

If I call the method startWithLoop I don't see any change in the view until the loop is finished.

Here is the JSFiddle

How can I trigger changes in the view on each step of the loop?

No, this is how Javascript eventloop works in browsers (and not only).

You can imagine that Javascript only gets executed in "gaps between moments", so that your picture of what happens in the browser is a still snapshot of the moment.

You could write something loop-like that uses setTimeout to let changes be noticed by Vue and then pushed to the DOM.

beforeDestroy() {
  if (this.timeout != null) {
    clearTimeout(this.timeout);
    this.timeout = null;
  }
},
startWithLoop: function() {
  console.log("startWithLoop");
  let i = 0
  const iter = () => {
    this.blink();
    i += 1;
    if (i < 10000) {
      this.timeout = setTimeout(iter);
    }
  }
  iter();
},

Working fiddle with the changes from above: https://jsfiddle.net/ssorallen/9pqscat1/3/

Wrapping up and as a merge of all the suggestions, I have understood that:

  • In the middle of a JS loop VueJS is not gonna re-render anything

So you have to move the iterations of your loop to another process. I was thinking that promises can be a solution but an easier one is to use setTimeout() without the delay param.

So instead of this:

for(var i = 0; i < 10000; i++ ) { 
  this.blink() 
};

My code would look like this:

for(var i = 0; i < 10000; i++ ) { 
  setTimeout(this.blink)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM