DEV Community

Idev.d
Idev.d

Posted on Originally published at idev.my

5 Practical Solutions for Large List Rendering in Vue 3

When rendering hundreds or thousands of items, Vue 3 apps can lag noticeably. We hit this problem in a recent inventory management system — 5,000 items caused 3-second load times and scrolling dropped below 15fps.

Here are 5 solutions we tested, ranked by effectiveness.

1. Virtual Scrolling (Best Overall)

Only render DOM elements within the visible viewport. We recommend vue-virtual-scroller:

<RecycleScroller :items="list" :item-size="60" key-field="id">
  <template #default="{ item }">
    <div class="item">{{ item.name }}</div>
  </template>
</RecycleScroller>
Enter fullscreen mode Exit fullscreen mode

Result: Initial render dropped from 3.2s to 0.1s. Memory from 180MB to 35MB.

2. Pagination + Infinite Scroll

Use the Intersection Observer API for load-on-scroll, fetching 20-50 items per request. Best when total data volume is unknown.

const observer = new IntersectionObserver(entries => {
  if (entries[0].isIntersecting) loadMore()
})
observer.observe(sentinel)
Enter fullscreen mode Exit fullscreen mode

3. v-memo Directive

Vue 3.2+'s v-memo caches subtree render results, skipping re-renders when dependent data hasn't changed:

<div v-for="item in list" :key="item.id" v-memo="[item.name, item.price]">
  <ExpensiveComponent :data="item" />
</div>
Enter fullscreen mode Exit fullscreen mode

Great for lists where individual items rarely change.

4. Web Worker Off-Thread Computing

Move computation-intensive operations like filtering and sorting to Web Workers:

const worker = new Worker('./listWorker.js')
worker.postMessage({ action: 'filter', data: rawList, query })
worker.onmessage = e => { filteredList.value = e.data }
Enter fullscreen mode Exit fullscreen mode

This prevents main thread blocking during heavy operations.

5. shallowRef + triggerRef

For large lists that don't need deep reactivity:

const list = shallowRef(hugeArray)
// After mutation:
triggerRef(list)
Enter fullscreen mode Exit fullscreen mode

Avoids Vue creating deep proxies for every element — significant memory savings.

Benchmark Summary

Solution Render Time (5K items) Memory
Default v-for 3.2s 180MB
Virtual Scrolling 0.1s 35MB
v-memo 1.8s 160MB
shallowRef 2.1s 90MB

Our recommendation: Virtual scrolling first, pagination second. They solve the root cause (too many DOM nodes) rather than optimizing around it.


Small team, big output. iDev builds web apps, AI solutions and custom systems with startup speed and enterprise quality. Based in Malaysia, serving Southeast Asia. Free consultation.

Top comments (0)