0

I came across a performance problem that boggles my mind. Given the following component:

<template lang="pug">
div
  div {{ counter }}
  div(v-for="idx in new Array(10000).keys()", :key="idx")
    b-button(v-on:click="increment()") ++
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class Test extends Vue {
  private counter = 0;

  increment() {
    console.log(Date.now());
    this.counter++;
  }
}
</script>

I expect that when I change counter vue does not rerender the full component. It seems I am wrong I get horrible performance when counter is changed. Am I missing something, is it how vue is supposed to work?

UPDATE

I replaced the new Array(10000).keys() call with a precomputed value but performance stays the same. Replacing b-button with a regular button improves performance significantly which indicates to me that for some reason all the buttons are recreated every time counter changes.

<template lang="pug">
div
  div {{ counter }}
  div(v-for="idx in keys", :key="idx")
    b-button(v-on:click="increment()") ++
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component
export default class Test extends Vue {
  private counter = 0;
  private keys = [...new Array(10000).keys()];

  increment() {
    console.log(Date.now());
    this.counter++;
  }
}
</script>

UPDATE

Removing the div {{ counter }} binding gives perfect performance (e.g. replacing with div 0).

1 Answer 1

1

The problem is that you are using a function inside and creating a new instance in the loop and then looping over it, so every time the counter update, that "new Array" again initiate.

UPDATE

The problem is with your "new Array(100).keys()", whenever you update "counter", it re-renders because of that.

And if you use instead of that place, normal array data, it will work and you won't get a re-render issue.

Use computed property:

dataArrayKey () {
            return [...new Array(10000).keys()]
          }

And then in the loop, use the computed property array, like this:

<template lang="pug">
div
  div {{ counter }}
  div(v-for="idx in dataArrayKey", :key="idx")
    b-button(v-on:click="increment()", :key="idx + '-button'") ++
</template>
Sign up to request clarification or add additional context in comments.

5 Comments

It is probably not that, even if I use computed property performance stays similar. Replacing b-button with regular button improves performance significantly, which indicates to me that it is probably recreating all the buttons for some reason every time counter changes.
@MarcinKról Got the problem, the problem is with this "new Array(100).keys()", it is normal Array and when you update, the Vue computed property thinks that you updated " Array(100).keys()", if you just use a normal array with data, it will fix your issue.
I replaced it with [...new Array(10000).keys()], I believe it creates a regular array. Unfortunately it changes nothing. Removing the {{ counter }} binding fixes performance so would it be the case if it was a problem with the array?
@MarcinKról with that clone array (with spread operator) in computed property, it also works.The problem is not the counter, it's I believe your "b-button" component. Maybe try to add "key" to it, it can fix the re-rendering issue.
It seems like the best option for now is to replace b-button (boostrap-vue component) with regular button. For some reason it is very inefficient. It is some very strange vue behavior though. This counter binding should in no way influence the b-button components.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.