JavaRush /Курсы /Модуль 3: React /Использование профилировщика для поиска проблемных мест

Использование профилировщика для поиска проблемных мест

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

Теперь это ваши проблемы

Вы когда-нибудь задумывались, как ваше приложение справляется со всеми своими задачами? Почему некоторые действия подтормаживают или страницы загружаются медленно? Тут как раз и начинается наша детективная работа — нужно выяснить, что происходит "под капотом". Профилирование позволяет не только понять, какие компоненты тратят слишком много ресурсов, но и оптимизировать их работу.

Цели профилирования

  1. Найти узкие места, которые замедляют работу приложения.
  2. Определить компоненты, которые рендерятся слишком часто без необходимости.
  3. Проанализировать длительные операции (например, сложные вычисления).
  4. Улучшить пользовательский опыт (UX) за счёт более отзывчивого интерфейса.

Если вас когда-нибудь раздражал тормозящий сайт, то поздравляю, теперь это ваши проблемы. И лично вам придется их решить :P

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

Для начала давайте установим React DevTools, если вы этого ещё не сделали. Это ваш основной инструмент профилирования. С его помощью можно увидеть, как работают компоненты, сколько времени тратится на их рендер и где именно нужно копать глубже.

Установка React DevTools

  1. Установите React DevTools как расширение для браузера Chrome или Firefox.
  2. Если вы работаете с локальным проектом, убедитесь, что он использует React версии >= 16.5 (именно с этой версии профилирование стало доступным).

После установки вы увидите новую вкладку в инструментах разработчика браузера — React. Переключитесь на неё и откройте интерфейс профилирования Profiler.

Запуск профилирования

Давайте разберём, как провести анализ производительности нашего React-приложения. Вот пример приложения, которое вы уже могли создавать в предыдущих лекциях:

import React, { useState, useEffect } from 'react';

type Todo = {
  id: number;
  title: string;
  completed: boolean;
};

const TodoItem: React.FC<{ todo: Todo }> = React.memo(({ todo }) => {
  console.log(`Rendering TodoItem: ${todo.id}`);
  return (
    <div>
      <input type="checkbox" checked={todo.completed} readOnly />
      <span>{todo.title}</span>
    </div>
  );
});

const App: React.FC = () => {
  const [todos, setTodos] = useState<Todo[]>([]);

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos')
      .then((response) => response.json())
      .then(setTodos);
  }, []);

  return (
    <div>
      <h1>Todo List</h1>
      {todos.map((todo) => (
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </div>
  );
};

export default App;

Это простое приложение с TodoItem, где мы загружаем и отображаем список дел. Однако, предположим, что оно подтормаживает. Как узнать, в чём проблема?

Запуск профайлера

  1. Откройте ваше приложение в браузере.
  2. Перейдите на вкладку React в DevTools.
  3. Нажмите на кнопку Profiler и начните запись Start Profiling.
  4. Выполните действие в приложении (например, пролистайте список).
  5. Остановите запись Stop Profiling и изучите результаты.

Интерпретация данных профилирования

После остановки профилирования вы увидите граф, который показывает, какие компоненты рендерились, сколько времени это заняло и что именно вызвало рендер.

Что искать?

  1. Долгие рендеры — компоненты, которые занимают наибольшую часть времени в общей схеме.
  2. Частые рендеры — компоненты, которые вызываются снова и снова без очевидной причины.
  3. Перерисовки без изменений — ситуации, когда компонент рендерится, хотя его пропсы/состояние не изменились.

🚨 Совет: если видите компонент, который рендерится слишком часто, это хороший кандидат для оптимизации с React.memo.

Пример оптимизации

В представленном выше приложении, если вы добавите лог в TodoItem, каждый вызов рендера этого компонента будет отображаться в консоли. Но на самом деле нам не нужно перерисовывать каждый компонент TodoItem, если меняется, например, только заголовок списка.

Чтобы исправить это, мы оборачиваем TodoItem в React.memo. Это мы уже сделали, чтобы предотвратить лишние рендеры. Но бывают случаи, когда объект todo сам по себе создаётся заново при каждом рендере App, из-за чего мемоизация не срабатывает. В таких случаях можно использовать useCallback или useMemo для предотвращения создания новых объектов.

{todos.map((todo) => (
  <TodoItem key={todo.id} todo={todo} />
))}

Проблема здесь в том, что каждый раз при рендере массив todos остаётся неизменным, но React всё равно может считать элементы вложенного компонента новыми. Исправим это.

Советы и лучшие практики при профилировании

  1. Находите главного виновника: не все медленные рендеры являются явной проблемой. Ищите основного виновника — компонент, который запускает цепную реакцию.

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

  3. Используйте React.memo и хуки с умом: излишнее применение может привести к усложнению кода.

  4. Типизируйте всё чётко: это не только помогает избежать ошибок, но и улучшает читаемость и поддержку кода.

  5. Тестируйте на различных устройствах: особенно важно для приложений, рассчитанных на мобильные устройства.

1
Задача
Модуль 3: React, 3 уровень, 8 лекция
Недоступна
Анализ производительности компонентов
Анализ производительности компонентов
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ