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
  • Двигается от симптома к гипотезам и проверкам
  • Отличает баг инструмента от ошибки использования или окружения

Related topics