Назад
Назад к заметкам
· 4 мин чтения

Профилирование React-приложения: ищем узкие места

Быстро находите узкие места в React-приложении с профилированием, чтобы ваш UI оставался отзывчивым.

reactperformancearchitecturestate-management

Если ваш список таблицы начал “тормозить”, а пользовательские действия стали заметно медленнее скорее всего, проблема скрывается в лишних рендерах или тяжелом расчете в UI-слое. Профилирование React-приложения позволяет увидеть узкие места в реальном времени и быстро принять решение, какие части кода нуждаются в “похолодании”. Профилирование React-приложения ваш первый шаг к измеримому улучшению производительности.

Обычные unit-тесты тут мало что скажут, потому что они проверяют только бизнес-логику, а не то, сколько времени тратит браузер на отрисовку. Профилирование React-приложения позволяет увидеть узкие места в реальном времени и быстро принять решение, какие части кода нуждаются в “похолодании”.


1. Почему стандартные метрики не работают для UI-оптимизации

В большинстве проектов измеряют производительность через показатели Time To First Paint или Largest Contentful Paint. Они дают общую картину, но не показывают, какие компоненты именно “залипают”. React-приложения часто страдают от избыточных ререндеров каждый рендер добавляет миллисекунды, а в сумме они становятся ощутимыми.

Tip: Если вы используете Redux, проверьте, не подписаны ли ваши компоненты на слишком большую часть стейта. Чтение большого дерева может спровоцировать лишние обновления.

2. Инструменты профилирования в арсенале фронтендера

ИнструментЧто измеряетКак включить
Chrome DevTools → PerformanceОбщие тайминги, JavaScript, Layout, PaintCtrl+Shift+I → Performance → Record
React Profiler (React DevTools)Количество ререндеров, длительность их выполненияВключить вкладку Profiler в React DevTools
why-did-you-render (npm)Подсказки о нежелательных рендерахnpm i @welldone-software/why-did-you-render

React Profiler ваш главный помощник в профилировании React-приложения. Он визуализирует рендер-дерево в виде Flamegraph, где каждый бар отдельный рендер компонента. Чем шире бар, тем дольше шел рендер.

Ссылка: Подробнее о работе Profiler можно почитать в React Profiler.

3. Как измерять рендеры программно

Для программного измерения рендеров в профилировании React-приложения React предоставляет API Profiler как компонент-обертку. Его колбэки позволяют собрать метрики в любой момент:

import { Profiler } from "react";

function onRender(
  id: string, // имя Profiler
  phase: "mount" | "update",
  actualDuration: number, // ms, затраченные на рендер
  baseDuration: number, // ms, без оптимизаций
  startTime: number,
  commitTime: number
) {
  console.log(`[${id}] ${phase} ${actualDuration.toFixed(2)}ms`);
}

export default function App() {
  return (
    <Profiler id="AppRoot" onRender={onRender}>
      <HeavyComponent />
    </Profiler>
  );
}

Собранные данные можно отправлять в Loki/Elastic для последующего анализа. Главное фиксировать actualDuration и сравнивать ее между версиями.

4. Поиск “тяжелых” компонентов и memo-оптимизации

После того как профайлер показал, какие компоненты рендерятся чаще всего, следующий шаг снизить их количество. Самый простой способ использовать мемоизацию.

import React, { memo } from "react";

function ListItem({ item }) {
  console.log("render", item.id);
  return <li>{item.title}</li>;
}

export default memo(ListItem); // запоминает результат, если props не изменились

memo работает как PureComponent для функциональных компонентов: если пропсы одинаковы рендер пропускается. При сложных вычислениях в пропсах стоит добавить useMemo или useCallback.

Ссылка: Подробнее о мемоизация компонентов поможет понять, когда стоит применять memo.

Частая ошибка

Не переусердствуйте: оборачивать каждый компонент в memo без анализа приводит к медленному сравнению props, особенно если они глубоко вложены. Лучше сначала профилировать, а потом мемоизировать.

5. Когда “много элементов” дело виртуализации списка

Если узкое место связано с рендером огромного списка (например, таблица из 10 000 строк), обычные оптимизации не спасут. Здесь на сцену выходит виртуализация рендерятся только те элементы, которые видимы в viewport.

import { FixedSizeList as List } from "react-window";

function Row({ index, style }) {
  const item = data[index];
  return <div style={style}>{item.title}</div>;
}

export default function VirtualizedTable() {
  return (
    <List height={600} itemCount={data.length} itemSize={35} width="100%">
      {Row}
    </List>
  );
}

react-window (или react-virtualized) экономит ресурсы, сокращая количество DOM-узлов. После внедрения виртуализации в профайлере обычно наблюдается резкое падение actualDuration у родительского списка.

Ссылка: Пример виртуализации в действии смотрите виртуализацию списка.

6. Чеклист для быстрой отладки

  • Проверьте количество ререндеров в React Profiler. Если один компонент участвует в более чем 30% всех рендеров ищите причину.
  • Отключите ненужные подписки на Redux/Context, чтобы снизить частоту обновлений стейта.
  • Добавьте memo только после профайлинга. Не используйте ее везде.
  • Виртуализируйте большие списки сразу, если их длина превышает 500-1000 элементов.
  • Не забывайте про useCallback при передаче функций вниз по дереву иначе каждый рендер будет создавать новый объект, ломая мемоизацию.

Эти пять пунктов покрывают 80 % типичных проблем с производительностью в React-проектах.


Наблюдать “тормоза” в продакшене страшно, но правильно настроенное профилирование React-приложения позволяет pinpoint-ировать узкие места и быстро их исправлять. При возникновении новых лагов просто запустите Profiler, посмотрите Flamegraph и применяйте описанные приемы. Пора перестать гадать и начать измерять.

Готов начать?

Выбери удобный способ связи — напиши напрямую или оставь заявку

Написать в Telegram

Отвечу в течение пары часов