Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як оптимізувати великі таблиці?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)Великі таблиці у Vue оптимізують пагінацією або віртуальним скролом, щоб не рендерити тисячі рядків одразу, мінімізацією реактивності (shallowRef/markRaw), правильним `key` у v-for і виносом важких обчислень у computed. **Ключове:** ключовий принцип - рендерити в DOM лише те, що дійсно видно користувачу, і не робити зайву реактивність там, де вона не потрібна.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## 1. Не рендерити все одразу: пагінація Найпростіше: - **показувати тільки частину даних** (10-50 рядків на сторінку) - решту - через кнопки/пагінацію/"показати ще" ```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) }) ``` Ще краще - **серверна пагінація**: отримувати з бекенду тільки потрібну сторінку. --- ## 2. Віртуалізація / windowing (viewport-only rendering) Для дуже великих таблиць (10k+ рядків) потрібна **віртуальна прокрутка**: - у DOM рендеряться тільки **видимі** рядки + невеликий буфер зверху/знизу - решта - просто порожнє місце з правильною висотою У Vue зазвичай використовують бібліотеки на кшталт: - `vue-virtual-scroller` - `vue-virtual-scroll-list` Приклад ідеї (умовний): ```vue <VirtualList :data-key="'id'" :data-sources="rows" :data-component="RowComponent" :kept-alive="50" /> ``` Це радикально знижує кількість DOM-елементів. --- ## 3. Мінімізувати реактивність даних Якщо таблиця просто відображає дані і самі рядки не редагуються: - не потрібно робити кожен рядок супер-реактивним - можна використовувати: - `markRaw` для великих об'єктів/масивів - `shallowRef` для всього списку ```js import { shallowRef, markRaw } from 'vue' const rows = shallowRef([]) // якщо приходять величезні об'єкти: rows.value = markRaw(bigArray) ``` Так Vue не буде глибоко відстежувати кожне вкладене поле. --- ## 4. Правильний `key` у v-for Обов'язково: ```vue <tr v-for="row in rows" :key="row.id"> ``` - стабільний унікальний `key` → Vue повторно використовує рядки - менше перестворень DOM-елементів - краща продуктивність при фільтрації/сортуванні **Не можна** використовувати індекс як key (`:key="index"`), якщо рядки можуть додаватися/видалятися/переставлятися. --- ## 5. Важка логіка - у computed, а не в шаблоні Не робити так: ```vue <td>{{ formatPrice(row.price) }}</td> <td>{{ complexCalculation(row) }}</td> ``` Краще: - заздалегідь прорахувати дані в `computed` - або підготувати поля до передавання в таблицю ```js const preparedRows = computed(() => rows.value.map(row => ({ ...row, priceLabel: formatPrice(row.price), total: calcTotal(row) })) ) ``` --- ## 6. Не створювати нові об'єкти/функції в шаблоні Кожен рендер: ```vue <Cell :options="{ align: 'right' }" /> ``` - створює новий об'єкт → Vue думає, що проп змінився → зайві оновлення. Винеси такі дані: ```js const rightAlignOptions = { align: 'right' } ``` ```vue <Cell :options="rightAlignOptions" /> ``` --- ## 7. Оптимізувати фільтрацію та сортування - фільтри/пошук → **debounce** на введення - сортування/фільтрація → у `computed`, а не в `watch deep` на весь масив - при величезних даних - делегувати сортування і фільтрацію серверу ```js const debouncedQuery = ref('') watch(query, debounce((v) => { debouncedQuery.value = v }, 300)) ``` --- ## 8. Спростити вміст комірок Всередині `<td>`: - менше складних компонентів - не рендерити те, що користувач все одно не бачить (умовні блоки, розкриття за кліком) - **ліниві деталі**: розкриваємо подробиці/детальні картки тільки за запитом --- ## 9. Не тягнути все в глобальний стор "про всяк випадок" Якщо величезна таблиця зберігається в глобальному store: - будь-яка зміна стора може тригерити багато компонентів - краще зберігати такі дані локально в сторінці/модулі --- ## 10. Візуально - скелетони і lazy-loading З точки зору UX: - показувати skeleton замість повної таблиці - підвантажувати дані порціями - не блокувати UI Це не зовсім "оптимізація рендеру", але сильно покращує сприйняття. --- ### Як це можна сказати на співбесіді (коротко): > Для оптимізації великих таблиць у Vue я: > > - використовую пагінацію або віртуальний скрол, щоб не рендерити тисячі рядків одразу; > - мінімізую реактивність (shallowRef/markRaw для великих структур); > - стежу за `key` у `v-for`, щоб Vue повторно використовував рядки; > - виношу важкі обчислення в `computed` і не створюю нові об'єкти/функції в шаблоні; > - за потреби роблю фільтрацію і сортування на сервері, а введення - з debounce.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.