Как ускорить React-приложение без переписывания всего кода

Большинство React-приложений тормозят не потому что React медленный — а потому что компоненты перерендериваются тогда, когда не должны, или загружают слишком много кода сразу. Хорошая новость: чаще всего можно ускориться без большого рефакторинга.

Сначала измерьте, потом оптимизируйте

Первая ошибка — начинать оптимизацию без данных. Прежде чем что-то менять, откройте React DevTools Profiler и посмотрите, какие компоненты рендерятся чаще всего и сколько времени занимает каждый рендер.

Запишите флейм-граф для типичного сценария: клик по кнопке, ввод в поле, прокрутка списка. Часто выясняется, что 80% времени уходит на один-два компонента, которые вы и не подозревали в проблемах.

React.memo и когда он не помогает

React.memo предотвращает рендер компонента, если его пропсы не изменились. Звучит просто, но есть нюанс: если родительский компонент каждый раз создаёт новые объекты или функции в JSX — memo не сработает, потому что сравнение пропсов по ссылке даст false.

Чтобы memo работал, нужно стабилизировать пропсы. Функции оборачивайте в useCallback, объекты — в useMemo. При этом сам useMemo тоже не бесплатный: добавляйте его только там, где вычисление действительно дорогое.

  • memo эффективен для листовых компонентов с примитивными пропсами
  • useCallback нужен, когда функция передаётся в memo-компонент
  • useMemo оправдан для фильтрации/сортировки больших массивов
  • Не оборачивайте всё подряд — overhead есть всегда

Code splitting: загружайте только то, что нужно сейчас

Если весь JavaScript загружается при первом открытии страницы — это почти всегда слишком много. React.lazy и Suspense позволяют загружать компоненты по требованию: модальные окна, вкладки, тяжёлые формы — всё, что пользователь видит не сразу.

В Next.js это ещё проще: dynamic импорт с { ssr: false } автоматически выносит компонент в отдельный чанк. Результат — меньше кода при первой загрузке, быстрее Time to Interactive.

Виртуализация: когда список длинный

Если вы рендерите больше 100-200 элементов за раз — скорее всего, стоит использовать виртуализацию. Библиотеки вроде @tanstack/virtual или react-window рендерят только видимые строки, а не весь список.

Прирост может быть колоссальным: список из 1000 строк без виртуализации рендерится за секунды, с виртуализацией — за миллисекунды. Особенно заметно на мобильных устройствах.

Что не стоит трогать

Не каждая оптимизация стоит своего времени. Если компонент рендерится 2 мс — это нормально. Если список из 20 элементов — виртуализация не нужна. Преждевременная оптимизация добавляет сложности без реальной пользы.

Хорошее правило: если пользователь не жалуется на тормоза и профайлер не показывает проблемных мест — значит, всё работает достаточно хорошо.

Источники и ссылки

Все статьи