Отладка состояния
Когда состояние ведёт себя странно — нужны инструменты и подходы.
React DevTools
Расширение для Chrome и Firefox. Показывает:
- Дерево компонентов
- Пропсы и стейт каждого компонента
- Кто кого рендерит
- Время рендера
Установка: React Developer Tools из магазина расширений.
Компоненты и хуки
В DevTools можно выделить компонент и увидеть его состояние. Для хуков — вкладка «Hooks».
console.log в рендере
Простой способ увидеть, сколько раз рендерится компонент:
function Component() {
console.log('render');
// ...
}
Если рендеров слишком много — ищи причину.
useEffect с логом
useEffect(() => {
console.log('state changed', state);
}, [state]);
Покажет, какие значения и когда менялись.
Почему компонент перерисовывается
React DevTools → Profiler → запись → взаимодействие. Покажет, какие компоненты рендерились и почему.
Бесконечный цикл
Признак: приложение зависает, в консоли сотни логов.
Причины:
setStateв теле компонента без условий- Объект или функция в зависимостях
useEffect useEffectбез зависимостей, который меняет стейт
// Бесконечный цикл
useEffect(() => {
setCount(count + 1);
}, [count]);
Устаревшее значение
Если в замыкании старое значение — используй функциональную форму или useRef.
// Плохо
useEffect(() => {
const id = setInterval(() => setCount(count + 1), 1000);
return () => clearInterval(id);
}, []);
// Хорошо
useEffect(() => {
const id = setInterval(() => setCount((c) => c + 1), 1000);
return () => clearInterval(id);
}, []);
Мутация стейта
Если UI не обновляется — проверь, не мутируешь ли стейт.
// Не сработает
items.push('new');
setItems(items);
// Сработает
setItems([...items, 'new']);
StrictMode
В dev-режиме React монтирует компоненты дважды. Эффекты выполняются дважды. Это нормально. Если что-то ломается — проверь очистку.
useEffect(() => {
const id = setInterval(...);
return () => clearInterval(id); // обязательно
}, []);
Логирование в dev
Полезно логировать переходы состояния в редьюсере:
function reducer(state: State, action: Action) {
console.log('action', action, 'state', state);
switch (action.type) {
// ...
}
}
Redux DevTools
Если используешь Redux — отдельное расширение. Показывает все действия и состояние после каждого.
Для Zustand есть middleware devtools:
import { devtools } from 'zustand/middleware';
export const useStore = create(devtools((set) => ({
// ...
})));
React Profiler
import { Profiler } from 'react';
<Profiler id="App" onRender={(id, phase, actualDuration) => {
console.log({ id, phase, actualDuration });
}}>
<App />
</Profiler>
Покажет время рендера компонентов.
Причины лишних рендеров
- Родитель рендерится → дети тоже
- Новый объект или функция в пропсах
- Контекст изменился
- Родитель передал новый
key
Решение: React.memo, useMemo, useCallback, разделение контекстов.
Итоги
- React DevTools — основной инструмент
- Profiler покажет лишние рендеры
- Бесконечный цикл — обычно зависимости
- Мутация — причина отсутствия обновлений
- Логирование редьюсера помогает
- Zustand devtools — для Zustand