Suggest an editImprove this articleRefine the answer for “How do you optimize large tables?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)Large tables in Vue are optimized with pagination or virtual scrolling so you don't render thousands of rows at once, by minimizing reactivity (shallowRef/markRaw), using a proper `key` in v-for, and moving heavy computations into computed. **Key point:** the core principle is to render in the DOM only what the user can actually see, and avoid unnecessary reactivity where it isn't needed.Shown above the full answer for quick recall.Answer (EN)Image## 1. Don't render everything at once: pagination The simplest approach: - **show only part of the data** (10-50 rows per page) - the rest, through buttons/pagination/"show more" ```vue <tr v-for="row in paginatedRows" :key="row.id"> ... </tr> ``` ```js const page = ref(1) const perPage = 50 const paginatedRows = computed(() => { const start = (page.value - 1) * perPage return rows.value.slice(start, start + perPage) }) ``` Even better: **server-side pagination**, fetching only the needed page from the backend. --- ## 2. Virtualization / windowing (viewport-only rendering) For very large tables (10k+ rows) you need **virtual scrolling**: - only the **visible** rows plus a small buffer above/below are rendered in the DOM - the rest is just empty space with the correct height In Vue, libraries like these are usually used: - `vue-virtual-scroller` - `vue-virtual-scroll-list` An example of the idea (illustrative): ```vue <VirtualList :data-key="'id'" :data-sources="rows" :data-component="RowComponent" :kept-alive="50" /> ``` This drastically reduces the number of DOM elements. --- ## 3. Minimize data reactivity If the table simply displays data and the rows themselves aren't edited: - you don't need to make every row super-reactive - you can use: - `markRaw` for large objects/arrays - `shallowRef` for the whole list ```js import { shallowRef, markRaw } from 'vue' const rows = shallowRef([]) // if huge objects arrive: rows.value = markRaw(bigArray) ``` This way Vue won't deeply track every nested field. --- ## 4. A proper `key` in v-for Always: ```vue <tr v-for="row in rows" :key="row.id"> ``` - a stable, unique `key` → Vue reuses rows - fewer DOM element recreations - better performance during filtering/sorting **Don't** use the index as the key (`:key="index"`) if rows can be added/removed/reordered. --- ## 5. Heavy logic goes into computed, not the template Don't do this: ```vue <td>{{ formatPrice(row.price) }}</td> <td>{{ complexCalculation(row) }}</td> ``` Better: - precompute the data ahead of time in `computed` - or prepare the fields before passing them into the table ```js const preparedRows = computed(() => rows.value.map(row => ({ ...row, priceLabel: formatPrice(row.price), total: calcTotal(row) })) ) ``` --- ## 6. Don't create new objects/functions in the template Every render: ```vue <Cell :options="{ align: 'right' }" /> ``` creates a new object → Vue thinks the prop changed → unnecessary updates. Extract such data: ```js const rightAlignOptions = { align: 'right' } ``` ```vue <Cell :options="rightAlignOptions" /> ``` --- ## 7. Optimize filtering and sorting - filters/search → **debounce** on input - sorting/filtering → in `computed`, not in a `watch deep` over the whole array - for huge data, delegate sorting and filtering to the server ```js const debouncedQuery = ref('') watch(query, debounce((v) => { debouncedQuery.value = v }, 300)) ``` --- ## 8. Simplify cell content Inside `<td>`: - fewer complex components - don't render what the user won't see anyway (conditional blocks, expand-on-click) - **lazy details**: expand details/detail cards only on request --- ## 9. Don't pull everything into the global store "just in case" If a huge table is stored in the global store: - any store change can trigger many components - it's better to keep such data local to the page/module --- ## 10. Visually: skeletons and lazy-loading From a UX standpoint: - show a skeleton instead of the full table - load data in chunks - don't block the UI This isn't strictly a "render optimization", but it greatly improves perception. --- ### How to phrase this in an interview (briefly): > To optimize large tables in Vue, I: > > - use pagination or virtual scrolling so I don't render thousands of rows at once; > - minimize reactivity (shallowRef/markRaw for large structures); > - watch the `key` in `v-for` so Vue reuses rows; > - move heavy computations into `computed` and avoid creating new objects/functions in the template; > - when needed, do filtering and sorting on the server, and debounce input.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.