How I optimized rendering in React
Как я оптимизировал рендер в React: реальный кейс с экономией 70% времени
Недавно я работал над дашбордом аналитики с сотнями строк в таблице и кучей графиков. Даже на мощном ноутбуке при скролле всё подтормаживало — профайлер показывал, что некоторые компоненты перерисовывались по 20–30 раз за одно действие. Я решил разобраться.
Первое, что я нашёл — огромный компонент TableRow, который рендерился целиком при любом изменении родителя. Решение было простым: обернул его в React.memo.
const TableRow = React.memo(({ row, onClick }) => { ... });
Эффект — мгновенный: лишних рендеров стало 0, но таблица всё ещё тормозила при фильтрации.
Вторым шагом я посмотрел на вычисления. В каждой строке считались сложные метрики (проценты, delta, цвет индикатора). Всё это пересчитывалось каждый раз, даже если данные не менялись. Добавил useMemo:
const metrics = useMemo(() => calculateHeavyMetrics(row), [row.id]);
Третье узкое место — контекст. Мы хранили весь стейт фильтров и сортировки в одном большом контексте, и каждый setFilter вызывал ререндер всей таблицы. Разбил на два контекста: один только для выбранной строки (редко меняется), второй — для фильтров. Плюс сделал useContextSelector (из библиотеки react-tracked), чтобы компоненты подписывались только на нужные кусочки.
Четвёртый приём — виртуализация. Перешёл с обычного <table> на react-window → FixedSizeList. Теперь рендерится только то, что видно на экране (15–20 строк вместо 500).
И последнее, что дало ещё30% скорости — заменил useState useEffect на useSyncExternalStore для подписки на изменения из WebSocket-канала. Теперь React не делает лишних ререндеров при одинаковых данных.
Результаты до и после:
| Метрика | Было | Стало | Улучшение |
|---|---|---|---|
| Время первого рендера | 1800 мс | 420 мс | ×4.3 |
| FPS при скролле таблицы | 22–28 | 58–60 | ×2.5 |
| Количество ререндеров/сек | ~340 | ~48 | ×7 |
Мораль простая: начинайте с React DevTools Performance tab → ищите самые тяжёлые компоненты → memo useMemo → виртуализация → гранулярный стейт. Часто 80% прироста дают 2–3 точечных изменения.