ReactSeniorExperience
Как понять, что проблема в проекте связана с React, а не с API, сетью, дизайном состояния или плохой архитектурой?
Локализация начинается с изоляции слоёв: Network tab для API/сети, React DevTools Profiler для рендеров, минимальный репро с мок-данными для самого React. Большинство 'багов React' — это устаревшие замыкания, неожиданные данные или проблемы окружения.
Как локализовать проблему в React-проекте
Большинство проблем в React-приложениях — не баги самого React, а неправильное использование его API, проблемы с данными, сетью или архитектурой. Диагностика начинается с построения гипотез и их систематического отклонения.
Шаг 1: Воспроизведение и изоляция
// Минимальный репро — изолируем компонент от приложения
import { useState, useEffect } from "react";
function IsolatedComponent() {
const [data, setData] = useState(null);
useEffect(() => {
// Заменяем реальный API на мок
const mock = { id: 1, name: "test" };
setData(mock);
}, []);
return <div>{JSON.stringify(data)}</div>;
}
Если баг воспроизводится с мок-данными — проблема в React-коде. Если нет — смотрим на API или сеть.
Шаг 2: Разделить слои
- Сеть / API: открываем Network tab в DevTools. Проверяем статус ответа, тело, время. Если API возвращает ошибку или неожиданные данные — проблема не в React.
- State: React DevTools → Profiler и Components. Смотрим, какие props/state получает компонент. Если данные правильные — проблема в рендеринге.
- React: лишние ре-рендеры (Profiler → «Why did this render?»), неправильный useEffect, устаревшие замыкания.
Шаг 3: Конкретные инструменты диагностики
// Диагностика лишних рендеров
import { useEffect, useRef } from "react";
function useRenderCount(name: string) {
const count = useRef(0);
count.current++;
useEffect(() => {
console.log(`[${name}] render #${count.current}`);
});
}
// Диагностика устаревшего замыкания в useEffect
function BadComponent({ userId }: { userId: string }) {
useEffect(() => {
// userId здесь — значение на момент первого монтирования
// если userId меняется, эффект не перезапускается
fetchUser(userId).then(console.log);
}, []); // БАГ: пустой массив зависимостей
// Фикс: }, [userId]);
}
Шаг 4: Сравнение окружений
- Баг только в production → проблема с минификацией, env-переменными или кешированием.
- Баг только в development → StrictMode двойной вызов эффектов (это норма, но выявляет нечистые эффекты).
- Баг только в Safari → проблема с Web API, а не React.
Шаг 5: Профилирование производительности
# Сборка с production-профилировщиком
REACT_APP_PROFILE=true npm run build
# В Chrome DevTools: Performance tab → Record → взаимодействие
# Ищем: длинные задачи (>50ms), частые Layout, лишние paint
Подводные камни
- StrictMode двойной вызов: в React 18 development эффекты вызываются дважды — это не баг, а проверка на идемпотентность. Не отключайте StrictMode для маскировки проблем.
- Кеш браузера vs React State: «данные не обновляются» часто — это кеш HTTP (ETag, Cache-Control), а не баг состояния.
- Ошибки в Next.js гидрации: «Hydration failed» — расхождение SSR/CSR HTML, а не баг React. Типичная причина —
new Date()илиMath.random()в компоненте. - Замыкания в useEffect: переменная внутри эффекта «захватывает» значение на момент создания — обновление через ref или добавление в deps.
- Обвинить React вместо данных: большинство «багов рендеринга» — это неожиданная форма данных из API (null вместо [], undefined вместо строки).
- Memory leak после размонтирования: async операция в useEffect без AbortController или флага mounted даёт setState после unmount — React 18 убрал warning, но leak остался.
- Production vs development bundle: React в production убирает propTypes и предупреждения — ошибки, видимые только в dev, могут скрывать реальные проблемы.
What hurts your answer
- Сразу обвинять React, не проверив соседние слои системы
- Чинить симптом без минимального воспроизведения и evidence
- Не учитывать версии, конфигурацию, окружение и recent changes
What they're listening for
- Умеет локализовать проблему вокруг React
- Двигается от симптома к гипотезам и проверкам
- Отличает баг инструмента от ошибки использования или окружения