Зачем использовать профилировщик?
Представьте, что вы ищете утечку воды в доме. Вы можете заменить все трубы, но, возможно, проблема только в одном месте. Точно так же с производительностью: нужно понимать, где именно проблема, перед тем как предпринимать действия. React DevTools — это "профессиональная камера для поиска утечек", которая поможет нам выявлять избыточные рендеры, долгие вычисления и другие проблемы.
Установка React DevTools
Если у вас ещё нет React DevTools, установите его:
- Откройте страницу React DevTools в вашем браузере.
- Установите расширение для Chrome или Firefox.
- Для локального проекта на
create-react-appили других сборщиках убедитесь, что React работает в режиме разработки.
После установки вы увидите вкладку React в панелях разработчика браузера.
Введение в профилирование React-приложения
React DevTools предоставляет вкладку Profiler, которая позволяет записывать производительность реактивных компонентов внутри приложения. Это похоже на запись ваших действий на камеру для последующего анализа.
Включение профилирования
- Откройте приложение в режиме отладки.
- Откройте инструменты разработчика браузера.
- Перейдите во вкладку React, затем — во вкладку Profiler.
- Нажмите "Start Profiling", чтобы начать запись производительности.
Анализ профиля
После записи профиля вы увидите графический интерфейс с рендерингом компонентов, их вызовами и временем выполнения. Давайте разберём ключевые элементы.
Основные элементы профилировщика
Флэймграф (Flamegraph):
- Похоже на перевёрнутую пирамиду.
- Каждый слой представляет компонент.
- Чем шире компонент, тем больше времени он занимает.
Индивидуальный рендеринг компонентов:
- Нажмите на конкретный компонент.
- В правой панели вы увидите, сколько времени заняло его рендеринг, и частоту изменений.
Причины рендеринга:
- Указывает, что вызвало повторный рендер.
- Например: изменение пропсов или стейта.
Практический пример: где проблема?
Представим, что у нас есть простое приложение по управлению задачами. Вот его структура:
import React, { useState } from "react";
const TaskList: React.FC = () => {
const [tasks, setTasks] = useState<string[]>(["Сделать React-приложение", "Помыть кота"]);
const [filter, setFilter] = useState("");
const filteredTasks = tasks.filter((task) => task.includes(filter));
return (
<div>
<input value={filter} onChange={(e) => setFilter(e.target.value)} placeholder="Поиск задач" />
<ul>
{filteredTasks.map((task, index) => (
<TaskItem key={index} task={task} />
))}
</ul>
</div>
);
};
const TaskItem: React.FC<{ task: string }> = ({ task }) => {
console.log(`Рендерится задача: ${task}`);
return <li>{task}</li>;
};
export default TaskList;
Где проблема?
- Запустим профилировщик. Вводим текст в поле фильтра.
- В Profiler мы видим, что каждый TaskItem снова рендерится при каждом вводе в поле! Даже если задача не меняется.
Как исправить?
Шаг 1: Мемоизация компонентов
Используем React.memo, чтобы предотвратить лишний рендер:
const TaskItem: React.FC<{ task: string }> = React.memo(({ task }) => {
console.log(`Рендерится задача: ${task}`);
return <li>{task}</li>;
});
Теперь в профилировщике видно, что только изменённые компоненты TaskItem рендерятся при вводе!
Шаг 2: Оптимизация фильтрации
Ещё один совет: если список задач стабилен, используйте useMemo для кэширования результата фильтрации.
import React, { useState, useMemo } from "react";
const TaskList: React.FC = () => {
const [tasks] = useState<string[]>(["Сделать React-приложение", "Помыть кота"]);
const [filter, setFilter] = useState("");
const filteredTasks = useMemo(() => {
return tasks.filter((task) => task.includes(filter));
}, [tasks, filter]);
return (
<div>
<input value={filter} onChange={(e) => setFilter(e.target.value)} placeholder="Поиск задач" />
<ul>
{filteredTasks.map((task, index) => (
<TaskItem key={index} task={task} />
))}
</ul>
</div>
);
};
Теперь профилировщик покажет, что фильтрация больше не выполняется на каждом рендере, а задача рендерится только при изменении filter.
Частые ошибки при профилировании
Запуск профилирования на продакшене: профилируйте только в режиме разработки! На продакшене React убирает некоторые проверки для скорости, что может повлиять на результаты.
Не забывайте о зависимостях: убедитесь, что все зависимости правильно указаны в
useMemoилиuseCallback.Слишком ранняя оптимизация: профилирование нужно для выявления реальных проблем, а не для "страха рендеров". Иногда лишние рендеры оправданы, если они не критичны для производительности.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ