Skip to content

Vuejs seems to struggle with v-model when many items on the page

I have a simle page containing a form at the top to submit some data and a list below that form as in the image:

enter image description here

The list is filled by data from an api and each object has 4 properties (not many for a simple list!). Currently the list has 130 elements in total. Now if I try to write something in the textarea, it happens to be very slow (2-10frames/sec). The more items added to the list, the slower it gets. The form at the top has a simple data object called form like below:

form: {
  description: '',
  expired: '',
  applicationId: ''
}

The funny part it that there is no single data shared between the list and the form at the top, so, they should operate independently. When I commend out the list section the textarea is very fast again.

Below is the code to render out the list:

  <b-card no-body class="box-shadowed">
    <b-card-body v-if="appKeys.length === 0">
      <h5>Seems there is no key available.</h5>
    </b-card-body>
    <b-list-group v-else flush>
      <b-list-group-item
        v-for="(key, index) in appKeys"
        :key="key.id"
      >
        <div class="d-flex w-100 justify-content-between">
          <p class="text-danger h6"><span class="text-dark">{{ index + 1 }} - </span> <i>{{ key.id }}</i></p>
          <div>
            <b-button variant="primary" title="Edit" @click="openEditModal(key.id, key.description, key.expired)">
              <b-icon :icon="'pencil'"/>
            </b-button>
            <b-button variant="danger" title="Delete" @click="deleteKey(index, key.id)">
              <b-icon :icon="'trash'"/>
            </b-button>
          </div>
        </div>
        <template v-if="key.expired">
          <b-badge variant="info">Expires on: {{ key.expired | formatDate }}</b-badge>
          <br/>
        </template>
        <small>
          <b>
            <i>Created by: {{ key.createdBy }}</i> on {{ key.created | formatDateTime }}
          </b>
          <br/>
          {{ key.description }}
        </small>

      </b-list-group-item>
    </b-list-group>

If I remove the v-model="form.description" from the textarea the problem goes away again. I thought that the problem might be the <b-form-textarea> component from bootstrap-vue but the same problem happens with a simple textarea input as well.

I tried checking the vue dev-tools panel and I can see that frames are dropping every time I have many items in the list but I dont know what else to check.

Does anybody have any idea why this might happen ? It is a vuejs limitation on how many items it can handle or I have some bottleneck code somewhere ?

EDIt

I Can use v-once and the page would be fast again but I need that reactivity when I add new elements to update the list below..

Answer

There is something what you have faced. Here says:

Any change to a template’s dependency will result of re-render of the whole virtual dom of that component.

While the list becomes larger and larger, there will be more components to be re-rendered. This results slowness. One of the solution is that you can create a child component for the html part where the list is. So, any input change in <b-form-textarea> in the parent component will not trigger the child component re-render.