← Назад к вопросам

Почему Hook нельзя использовать в условиях?

1.8 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Почему Hooks нельзя вызывать в условиях или циклах

Основная причина запрета на вызов Hooks в условиях, циклах или вложенных функциях связана с тем, как React управляет их состоянием внутри компонента.

Механизм работы Hooks в React

React использует порядок вызова Hooks для отслеживания состояния между рендерами. Когда вы вызываете useState, useEffect или другой Hook, React добавляет его в внутренний связанный список (или массив) Hooks для этого компонента.

// Пример компонента
function MyComponent() {
  const [name, setName] = useState('Анна');    // Hook #1
  const [age, setAge] = useState(30);          // Hook #2
  const [city, setCity] = useState('Москва');  // Hook #3
  
  useEffect(() => {                           // Hook #4
    document.title = `${name}, ${age}`;
  });
  
  // ... остальной код
}

При каждом рендере React проходит по этому списку Hooks в строго определенном порядке. Каждый Hook получает данные из своей "ячейки" в этом внутреннем массиве.

Что происходит при условном вызове

Рассмотрим проблемный пример:

function ProblematicComponent({ isAdmin }) {
  const [userData, setUserData] = useState(null);  // Hook #1
  
  if (isAdmin) {
    const [adminData, setAdminData] = useState({}); // Hook #2 (условный!)
  }
  
  const [settings, setSettings] = useState({});     // Hook #3
  
  // ... рендер
}

Проблема возникает при повторных рендерах:

  1. Первый рендер: isAdmin = true → Hooks: [#1, #2, #3]
  2. Второй рендер: isAdmin = false → Hooks: [#1, #2, #3]

React по-прежнему будет ожидать три Hooks в том же порядке, но второй Hook (useState для adminData) не будет вызван. Это приводит к нарушению соответствия между вызовами Hooks и внутренним состоянием React. В результате settings получит значение, предназначенное для adminData, что вызовет ошибки и неожиданное поведение.

Фундаментальные правила Hooks

React требует соблюдения Rules of Hooks по следующим причинам:

  1. Согласованность состояния между рендерами
    Каждый Hook должен вызываться одинаковое количество раз и в одинаковом порядке при каждом рендере компонента.

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

    • Один Hook получит состояние другого Hook
    • Эффекты будут выполняться неправильно
    • Компонент будет использовать устаревшие или неправильные значения
  3. Статический анализ
    ESLint плагин eslint-plugin-react-hooks может статически обнаруживать нарушения, что предотвращает ошибки на этапе разработки.

Правильные альтернативы

Вместо условного вызова Hooks, используйте условную логику внутри Hooks или условный рендер компонентов:

// ✅ ПРАВИЛЬНО: Условный эффект
function UserProfile({ userId, isAdmin }) {
  const [userData, setUserData] = useState(null);
  
  useEffect(() => {
    if (isAdmin) {
      // Загружаем дополнительные данные для админа
      fetchAdminData(userId).then(setUserData);
    }
  }, [userId, isAdmin]);
  
  // ✅ ПРАВИЛЬНО: Условный возврат значения
  const adminSettings = useMemo(() => {
    return isAdmin ? calculateAdminSettings() : null;
  }, [isAdmin]);
  
  return (
    <div>
      {/* Условный рендер другого компонента с Hooks */}
      {isAdmin && <AdminPanel />}
    </div>
  );
}

// ✅ ПРАВИЛЬНО: Вынесение условной логики в отдельный компонент
function AdminPanel() {
  // Все Hooks вызываются безусловно внутри этого компонента
  const [adminData, setAdminData] = useState({});
  // ... другие Hooks
}

Исключение: Custom Hooks

Custom Hooks могут содержать условную логику, но сами вызовы Hooks внутри них также должны следовать правилам — вызываться одинаково при каждом выполнении Custom Hook.

// ✅ Custom Hook с условной логикой
function useUserData(userId, options = {}) {
  const [data, setData] = useState(null);
  
  // Условная логика ВНУТРИ эффекта - допустимо
  useEffect(() => {
    if (options.autoFetch && userId) {
      fetchUserData(userId).then(setData);
    }
  }, [userId, options.autoFetch]);
  
  return data;
}

Заключение

Запрет на условный вызов Hooks — это не произвольное ограничение, а фундаментальное требование архитектуры React, которое обеспечивает корректную работу системы управления состоянием. React полагается на неизменный порядок вызовов Hooks для связывания состояния между рендерами. Нарушение этого порядка приводит к ошибкам, которые сложно отлаживать, так как они проявляются как непредсказуемое поведение компонентов. Правильное использование Hooks — залог стабильной и предсказуемой работы React-приложений.