JavaRush /Курсы /Модуль 3: React /Профилирование компонентов и анализ производительности — ...

Профилирование компонентов и анализ производительности — React DevTools

Модуль 3: React
25 уровень , 1 лекция
Открыта

Вспоминаем, что такое профилирование

Если бы ваше приложение умело разговаривать, оно бы, вероятно, сразу пожаловалось: «меня рендерят слишком часто», «меня заставляют пересчитывать тяжёлую функцию каждую секунду» или «я не успеваю обновляться». Чтобы услышать эти жалобы и разобраться, где именно приложение страдает, и существует профилирование компонентов.

Профилирование — это процесс анализа производительности приложения, позволяющий выявить узкие места и избыточные ререндеры. С помощью встроенного профайлера в React DevTools можно увидеть:

  • Какие компоненты рендерились и сколько времени на это ушло;
  • Какие изменения привели к ререндеру;
  • Где тратится слишком много ресурсов и как этого избежать.

Где тратится слишком много ресурсов и как этого избежать.

Установка и настройка React DevTools в Expo

В обычном React Native проекте часто используют Flipper. Но если вы работаете с Expo, вам повезло — вам ничего не нужно вручную интегрировать. Expo уже предоставляет поддержку React DevTools и включает в себя удобный интерфейс — Expo DevTools.

Что нужно сделать:

  1. Установите React DevTools на ваш компьютер (если ещё не установлены).
    npm install --save-dev react-devtools
  2. Запустите Expo-проект:
    npx expo start
  • Expo DevTools откроется в браузере. Там можно включить поддержку React DevTools и подключиться к приложению.
  • Откройте React DevTools отдельно (через ярлык или вручную), и вы увидите ваше дерево компонентов.
  • Перейдите на вкладку Profiler, нажмите "Record", выполните действия в приложении и остановите запись — всё готово к анализу.

Если вы используете Expo Go на телефоне, убедитесь, что и телефон, и компьютер находятся в одной Wi-Fi-сети.

Использование профайлера React DevTools

Вот пошагово, как работать с профайлером:

  1. Запуск профилирования: Откройте вкладку Profiler в React DevTools, нажмите кнопку Record, и начните взаимодействие с приложением: переходите по экранам, вводите текст, нажимайте кнопки.
  2. Поймайте рендер: Сделайте любое действие, которое может вызвать ререндер компонентов, затем нажмите Stop.
  3. Изучение результатов: Вы увидите граф с компонентами и временем их отрисовки. Цветные полосы показывают, какие компоненты "тяжёлые", и как часто они перерисовывались.

Например:

App - 20ms
  - Header - 5ms
  - TransactionList - 12ms
    - TransactionItem x 10 - 1ms каждый

Интерпретация данных: как понять, что тормозит?

Тяжёлые компоненты

Если компонент consistently рендерится дольше 15-20ms, стоит задуматься. Например:

const HeavyComponent = () => {
  const calculate = () => {
    let total = 0;
    for (let i = 0; i < 1000000; i++) total += i;
    return total;
  };

  return <Text>{calculate()}</Text>;
};

Здесь каждое изменение вызывает долгий расчёт. Решение — useMemo:

const HeavyComponent = () => {
  const total = useMemo(() => {
    let sum = 0;
    for (let i = 0; i < 1000000; i++) sum += i;
    return sum;
  }, []);

  return <Text>{total}</Text>;
};

Лишние рендеры

Вы видите, что компонент перерендеривается без видимых причин? Возможно, ему передаются новые (по ссылке) пропсы каждый раз:

const MemoComponent = React.memo(({ value }: { value: number }) => {
  console.log('Рендер');
  return <Text>{value}</Text>;
});

const Parent = () => {
  const [count, setCount] = useState(0);

  return (
    <>
      <MemoComponent value={count} />
      <Button title="+" onPress={() => setCount(count + 1)} />
    </>
  );
};

Если value не меняется, MemoComponent не должен рендериться. Но если вы передаёте функции, объекты или массивы без useCallback / useMemo, это может ломать мемоизацию.

Сложные списки и виртуализация

Если вы отрисовываете большой список (например, список транзакций), используйте FlatList вместо обычного .map:

const items = Array.from({ length: 1000 }, (_, i) => `Item ${i}`);

return (
  <FlatList
    data={items}
    keyExtractor={(item) => item}
    renderItem={({ item }) => <Text>{item}</Text>}
  />
);

Или даже FlashList из @shopify/flash-list, если список действительно большой.

Практический пример: от плохого к хорошему

Плохо

{items.map((item) => (
  <Text key={item}>{item}</Text>
))}

Все элементы будут перерисовываться на каждом обновлении.

Лучше

const Item = React.memo(({ label }: { label: string }) => {
  console.log(`Рендер: ${label}`);
  return <Text>{label}</Text>;
});

<FlatList
  data={items}
  keyExtractor={(item) => item}
  renderItem={({ item }) => <Item label={item} />}
/>

Теперь Item будет рендериться только при изменении своих пропсов.

Типичные ошибки и советы

  1. Забыли остановить запись профайлера — и получили график на 10 минут, в котором ничего не понятно.
  2. Передаёте функции без useCallback — из-за этого React.memo не работает.
  3. Играетесь со стилями inline — если style={{}} создаётся при каждом рендере, это ломает мемоизацию и вызывает лишние обновления.
  4. Не используете FlatList при длинных списках — тормоза гарантированы.
2
Задача
Модуль 3: React, 25 уровень, 1 лекция
Недоступна
Оптимизация лишних рендеров с помощью React.memo
Оптимизация лишних рендеров с помощью React.memo
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ