Ok, my situation is the following... I have to render a list in vue based on items that are fetched by axios. Each item has an id, a code (string) and a description and I have 14.000 of these items inside the system's db (mysql). Also, these Items are divided in 119 categories that also have a code and a description (some categories have more items than others). My job is to show a list of these categories in a way that every time someone clicks on a category, it collapses to show the category's list of items.
My current solution: everytime someone clicks on a category, the system makes an axios get request to fetch the category's items (it returns an array of objects) and then I render them using v-for. To fetch the correct items, I've built an specific query using knex (nodejs backend). The problem is that when I click a category that has many items or if I click a lot of categories kinda fast, the website becomes very slow and sometimes it just stops completely. So I wanna know what is the proper and optimized way of rendering long lists in vue.
My code for the axios request:
getCategoryItems(index) {
this.isOpen = index
this.loading()
const cat = this.categories[index].code
this.$axios
.get('/api/items', {
params: {
category: cat
}
})
.then(response => {
this.categoryItems = response.data
})
.catch(error => {
console.log(error)
})
}
My code for the rendering the list (I'm using buefy):
<section ref="modalContent" class="modal-card-body">
<b-collapse
v-for="(category, index) of categories"
:key="index"
:open="isOpen == index"
@open="getCategoryItems(index)"
class="card"
animation="slide"
>
<template #trigger="props">
<div class="card-header" role="button">
<p class="card-header-title">
{{ category.description }}
</p>
<a class="card-header-icon">
<b-icon :icon="props.open ? 'menu-down' : 'menu-up'"> </b-icon>
</a>
</div>
</template>
<div class="card-content">
<div ref="content" class="content">
<div v-for="item in categoryItems" :key="item.id" class="category-item">
<b-icon icon="book-plus" size="is-small"> </b-icon>
<a @click="selectedItem(item)" class="category-item-title">
{{ item.description }}
</a>
</div>
<b-loading :is-full-page="false" v-model="isLoading"></b-loading>
</div>
</div>
</b-collapse>
</section>
CodePudding user response:
Quite honestly there is no right answer to you here besides:
You should paginate the results
What is pagination (assuming you are using a REST API)
If you truly want to render all of those results you still have the option to use virtual scrollers. Virtual scrollers allow you to render millions of records without having to render all of them at once in the DOM.
How to use virtual scrollers is beyond the scope of this answer. Feel free to view the link I have sent you