PassFront
  1. PassFront
  2. База знаний
  3. Рендеринг и производительность

Как оптимизировать React приложение, если страница подвисает при действиях пользователя?

Рендеринг и производительность

«Подвисает при действиях пользователя» — значит главный поток занят: ввод, клики и анимации ждут, пока React (или ваш код) закончит работу. Лечение — по причине.

Сначала измерить

React DevTools Profiler (production-сборка): что рендерится на каждое действие и сколько стоит. Performance-запись в Chrome: длинные задачи (>50 мс), что именно в них — рендер, вычисления, layout. Метрика INP показывает реальную отзывчивость.

Причина 1: слишком много рендеров

Состояние ввода лежит слишком высоко — на каждый символ рендерится вся страница.

  • Спустить state вниз, к полю.
  • children-как-проп, чтобы обёртка со state не перерисовывала детей.
  • React.memo на тяжёлых соседях + стабильные props (useCallback/useMemo).
  • Разделить контексты, сузить селекторы стора.

Причина 2: рендер дорогой

  • useMemo на тяжёлые вычисления (фильтрация/сортировка тысяч строк).
  • Виртуализация больших списков и таблиц (react-window/virtuoso), если в DOM тысячи узлов, мемоизация не спасёт.

Причина 3: срочное соревнуется с несрочным

Ввод блокируется тяжёлой перерисовкой результатов:

const [isPending, startTransition] = useTransition();
const onChange = (e) => {
  setQuery(e.target.value);                    // срочно: поле
  startTransition(() => setFilter(e.target.value)); // несрочно: список
};

Или useDeferredValue(query) для тяжёлого поддерева. Плюс дебаунс дорогих реакций.

Причина 4: тяжёлые вычисления вне рендера

Парсинг, шифрование, обработка изображений — вынести в Web Worker; длинные циклы разбивать.

Причина 5: layout thrashing

Чередование чтения (getBoundingClientRect) и записи стилей в цикле; тяжёлый useLayoutEffect блокирует кадр.

Коротко для собеседования

Профилировать (Profiler + Performance + INP), затем: убрать лишние рендеры (state вниз, memo, стабильные props, селекторы), удешевить рендер (useMemo, виртуализация), развести приоритеты (useTransition/useDeferredValue, дебаунс), тяжёлые вычисления — в Web Worker, не допускать layout thrashing.

Другие вопросы раздела