Разделение кода, ленивая загрузка и виртуализация
Урок про разделение кода (React.lazy + Suspense) и про идею виртуализации длинных списков — две техники, которые ускоряют не рендер, а загрузку и объём DOM.
Разделение кода (code splitting) — разбиение бандла на части, которые грузятся по требованию. Виртуализация — отрисовка только видимой части длинного списка.
Проблема: один огромный бандл
По умолчанию сборщик складывает весь JS в один файл. Пользователь, открывший главную, скачивает и код страницы настроек, и админку, и тяжёлый редактор — всё сразу. Это медленный первый запуск. Решение — грузить редко используемые куски лениво, когда они действительно нужны.
React.lazy и Suspense
React.lazy принимает функцию, которая динамически импортирует компонент. Сборщик выделит этот компонент в отдельный чанк. Пока чанк грузится, Suspense показывает запасной UI (fallback).
import React, { Suspense } from "react";
// чанк с Dashboard скачается только когда компонент понадобится
const Dashboard = React.lazy(() => import("./Dashboard"));
function App({ showDashboard }) {
return (
<Suspense fallback={<p>Загрузка…</p>}>
{showDashboard && <Dashboard />}
</Suspense>
);
}
Типичные точки разделения: маршруты (каждая страница — свой чанк), тяжёлые модальные окна, редакторы, графики, всё, что не нужно на первом экране. Один Suspense может оборачивать несколько ленивых компонентов и показывать общий индикатор загрузки.
Когда code splitting оправдан
- Бандл большой, и есть код, который нужен лишь части пользователей или лишь на определённых экранах.
- Маршрутизация: ленивые маршруты — почти всегда хорошая идея в средних и крупных приложениях.
- Не дробите слишком мелко: десятки крошечных чанков создают накладные расходы на сетевые запросы. Разумная гранулярность — страница/крупная фича.
Виртуализация длинных списков — идея
Представьте таблицу на 10 000 строк. Даже если каждый рендер дёшев, в DOM окажется 10 000 узлов — браузеру тяжело их разместить и прокручивать. Виртуализация (она же «оконный рендеринг», windowing) решает это так: отрисовывается только то, что попадает в видимую область прокрутки, плюс небольшой запас сверху и снизу. При скролле компоненты переиспользуются, подставляя данные следующих строк, а общая высота имитируется отступом-распоркой.
| Подход | Узлов в DOM для 10 000 строк |
наивный map | ~10 000 (тяжёлый DOM, лаги скролла) |
| виртуализация | ~20–40 (только видимые + запас) |
На практике виртуализацию не пишут руками — берут библиотеку (react-window, react-virtuoso, @tanstack/react-virtual). Применяйте её, когда список реально длинный (сотни–тысячи строк) и тормозит. Для коротких списков это лишняя сложность.
Итог
React.lazy+Suspenseгрузят компоненты по требованию, ускоряя первый запуск.- Лучшие точки разделения — маршруты и тяжёлые редко используемые фичи.
- Виртуализация рендерит только видимые строки списка — лекарство от тяжёлого DOM.
- Обе техники — про «не делать лишнего заранее»; нужны под реальную нагрузку, а не везде.