Уявіть: список із 10 000 товарів в адмінці під час прокручування завмирає на секунди. Або дашборд з графіками оновлюється ривками, а модальне вікно відкривається із затримкою в півсекунди. Це типові симптоми неоптимального рендерингу, часто спричинені неефективною роботою Virtual DOM. Ми — команда веб-розробників із 10-річним стажем — щодня стикаємося з такими задачами. Наша мета — усунути зайві ре-рендери, віртуалізувати важкі списки та оптимізувати DOM-операції. Віртуалізація списків React — ключовий прийом для прискорення прокручування, а оптимізація рендерингу потребує системного підходу. За роки роботи ми виконали понад 50 проєктів з performance-оптимізації, і кожного разу підхід єдиний: виміряти, знайти вузьке місце, застосувати точкове рішення. Гарантуємо підвищення Core Web Vitals до зелених зон. Вартість аудиту починається від 500$.
Як виміряти продуктивність React-додатку?
До початку оптимізації визначаємо baseline. Використовуємо React DevTools Profiler: записуємо сесію, знаходимо компоненти з high render duration і частими ре-рендерами. Також Chrome Performance — long tasks (>50 ms), Recalculate Style, Layout thrashing. Для швидкої перевірки застосовуємо Profiler API. Це перший крок: вирішуємо, чи потрібна віртуалізація, мемоізація або рефакторинг стану. Типові метрики: LCP >2.5s, INP >200ms, TTFB >800ms — сигнал до дії. Аудит продуктивності React починається з профілювання та виявляє вузькі місця.
Віртуалізація списків: TanStack Virtual vs react-window
DOM із 1000+ вузлів — убивця продуктивності. Браузер тримає все в пам'яті, scroll handler перебирає кожен елемент. Віртуалізація рендерить лише видимі рядки + overscan. Вибір бібліотеки залежить від задачі.
TanStack Virtual — headless, не диктує стилі, підтримує динамічні висоти через measureElement.
import { useVirtualizer } from '@tanstack/react-virtual'; function VirtualList({ items }) { const parentRef = useRef(null); const virtualizer = useVirtualizer({ count: items.length, getScrollElement: () => parentRef.current, estimateSize: () => 50, overscan: 5, }); return ( <div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}> <div style={{ height: virtualizer.getTotalSize() + 'px', position: 'relative' }}> {virtualizer.getVirtualItems().map(virtualItem => ( <div key={virtualItem.key} style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: virtualItem.size + 'px', transform: `translateY(${virtualItem.start}px)` }}> {items[virtualItem.index].name} </div> ))} </div> </div> ); } react-window — простіший для таблиць із фіксованими рядками.
import { FixedSizeList as List } from 'react-window'; const Row = ({ index, style }) => ( <div style={style}>Row {index}</div> ); <List height={400} itemCount={10000} itemSize={35} width={300}> {Row} </List> | Feature | react-window | @tanstack/react-virtual |
|---|---|---|
| Headless | Ні | Так |
| Dynamic size | Ні | Так (measureElement) |
| TypeScript | Так | Так |
| Bundle size | ~5 kB | ~3 kB |
| Community | Велика | Зростаюча |
За нашим досвідом, TanStack Virtual краще за react-window в 1.5 раза за гнучкістю — це робить його найкращим вибором для складних інтерфейсів із кастомними елементами. react-window залишається еталоном для типових таблиць. Віртуалізація списків знижує споживання пам'яті до 90% і забезпечує плавне прокручування навіть на слабких пристроях. Віртуальний скрол — техніка відмальовування лише видимих елементів.
Чому віртуалізація списків критична для Core Web Vitals?
Без віртуалізації браузер створює тисячі DOM-вузлів, що збільшує час відмальовування та споживання пам'яті. Це прямо погіршує LCP (Last Contentful Paint) та INP (Interaction to Next Paint). Core Web Vitals — метрики якості користувацького досвіду. Віртуалізація зменшує кількість вузлів до видимої області, скорочуючи LCP на 30–50% та INP на 60% у наших проєктах. Наприклад, в одному інтернет-магазині після впровадження TanStack Virtual LCP знизився з 4.2 до 1.8 секунди, а INP — з 350 до 120 мс.
Як позбутися зайвих ре-рендерів?
Profiler показує, що компонент рендериться без причини. Часті сценарії та рішення:
- Нові об'єкти або функції на кожен рендер — використовуємо
useCallbackдля стабілізації посилань. - Компоненти з дорогим рендером обгорнуті в
memoз кастомним компаратором. - Дорогі обчислення — виносимо в
useMemo. - Контексти — розділяємо за частотою оновлень, застосовуємо
use-context-selectorдля точкової підписки.
const handleClick = useCallback((id) => doSomething(id), []); const Card = memo(({ item }) => <div>{item.name}</div>, (prev, next) => prev.item.id === next.item.id); Ці техніки дозволяють знизити кількість ре-рендерів у 3–10 разів, що прямо покращує INP та загальну чуйність. React memo та useCallback допомагають стабілізувати рендер, усунення ре-рендерів — ключ до плавного UI.
Важкі обчислення виносимо в Web Worker
Фільтрація мільйона записів не повинна блокувати UI. Web Workers звільняють main thread для взаємодій. Веб-воркери (Web Workers) покращують продуктивність фронтенду.
// worker.ts self.onmessage = (e) => { const result = e.data.items.filter(/* ... */); self.postMessage(result); }; // usage const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' }); worker.onmessage = (e) => setFiltered(e.data); worker.postMessage({ items, filters }); Використання transferable objects скорочує копіювання даних, знижуючи затримки при сортуванні та пошуку. В одному проєкті це зменшило час фільтрації з 2 секунд до 50 мс.
Покроковий план оптимізації
Типові помилки при оптимізації та як їх уникнути:
- Застосовувати віртуалізацію до списків з частими змінами висоти — використовуйте
measureElement. - Забувати про overscan — додайте 5–10 елементів для плавного скролу.
- Мемоізувати все підряд — перевіряйте реальну користь через Profiler.
- Ігнорувати контекст — розділяйте часті та рідкісні оновлення.
- Не тестувати на мобільних пристроях — емулюйте CPU slowdown.
Кроки:
- Профілювання. Запишіть сесію React DevTools, знайдіть компоненти з частими ре-рендерами та long tasks.
- Ідентифікація вузьких місць. Визначте, чи потрібна віртуалізація, мемоізація чи винесення обчислень у воркер.
- Вибір інструмента. Для списків — TanStack Virtual або react-window; для мемоізації — memo/useCallback/useMemo; для обчислень — Web Worker.
- Реалізація. Впровадьте зміни за пріоритетом: спочатку найзатратніше за часом.
- Валідація. Порівняйте метрики LCP, INP, TTFB до та після. Повторіть цикл за потреби.
Що входить у нашу роботу з оптимізації?
| Етап | Тривалість | Результат |
|---|---|---|
| Аудит продуктивності | 1–2 дні | Звіт з рекомендаціями, заміри LCP/INP/TTFB |
| Реалізація оптимізацій | 1–3 тижні | Віртуалізація, мемоізація, рефакторинг стану |
| Тестування та валідація | 2–3 дні | Порівняння метрик до/після, перевірка на різних пристроях |
| Документація та навчання | 1 день | Опис змін, інструкції для команди |
Терміни: від 1 дня на аудит до 2–4 тижнів на комплексний рефакторинг великого SPA. Вартість розраховується індивідуально, аудит від 500$.
Отримайте консультацію: оцінимо ваш проєкт і запропонуємо roadmap оптимізації. Зв'яжіться з нами.







