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

Почему нельзя использовать хуки внутри условного рендеринга?

2.0 Middle🔥 131 комментариев
#JavaScript Core#React

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

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

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

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

Ключевая причина заключается в механизме работы React с списком хуков (hook list), который напрямую связан с порядком их вызова. React полагается на стабильный, неизменный порядок вызова хуков между рендерами одного и того же компонента. Нарушение этого порядка ведёт к сбоям и неожиданным ошибкам.

Как React отслеживает хуки внутри компонента

Для функционального компонента React внутренне создаёт связанный список хуков. Каждому вызову хука (например, useState, useEffect) соответствует запись в этом списке. При последующих рендерах React сопоставляет значения хуков и их состояние именно по позиции (индексу) в этом списке, а не по имени переменной или каким-либо другим признакам.

// Пример компонента, где порядок хуков стабилен между рендерами
function StableComponent() {
  const [name, setName] = useState('Анна'); // Хук №1 в списке
  const [age, setAge] = useState(30);      // Хук №2 в списке
  useEffect(() => { /* эффект */ });       // Хук №3 в списке

  return <div>{name}, {age} лет</div>;
}

Между рендерами React ожидает, что вызов useState('Анна') ВСЕГДА будет первым, useState(30) — вторым, а useEffect — третьим. Это позволяет корректно сохранять и восстанавливать состояние.

Что происходит при использовании хука в условии

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

function UnstableComponent({ isAdmin }) {
  if (isAdmin) {
    const [adminData, setAdminData] = useState(null); // Хук вызывается условно!
  }
  const [userData, setUserData] = useState(''); // Позиция этого хука меняется

  // ... остальной код
}

Сценарий, ведущий к сбою:

  1. Первый рендер: isAdmin = true.
  • Список хуков: [useState(null) (админ), useState('') (пользователь)].
  1. Второй рендер: isAdmin = false.
  • React ожидает тот же порядок хуков, но первый вызов useState теперь должен соответствовать adminData. Однако условие false, поэтому первым выполняется useState('').
  • Для React это выглядит так: "На первом месте теперь useState('')? Значит, это хук для adminData, и его начальное состояние — null. Но в коде ему передаётся ''. Произойдёт подстановка неверного значения (null вместо '') или вызовется ошибка.

На практике React выбрасывает ошибку: "Rendered fewer hooks than expected" или "React Hook "useState" is called conditionally".

Технические последствия нарушения порядка

  • Перепутанное состояние: Состояние одного хука может быть присвоено переменной другого хука.
  • Сломанные эффекты: Зависимости useEffect, useMemo, useCallback будут связаны не с теми хуками.
  • Критические ошибки: Приложение может упасть с сообщением о нарушении "Rules of Hooks".

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

Чтобы использовать логику условно, но соблюдать правила хуков, применяйте следующие подходы:

  • Выносите условие ВНУТРЬ хука:
function CorrectComponent({ isAdmin }) {
  const [userData, setUserData] = useState('');
  // Условие внутри хука эффекта — допустимо
  useEffect(() => {
    if (isAdmin) {
      // Загрузка данных для админа
    }
  }, [isAdmin]);
}
  • Поднимайте состояние вверх и используйте композицию компонентов:
function AdminPart() {
  const [adminData, setAdminData] = useState(null); // Хук вызывается стабильно
  return <div>Админ-панель</div>;
}

function UserComponent({ isAdmin }) {
  const [userData, setUserData] = useState(''); // Хук всегда на первом месте
  return (
    <div>
      <div>Данные пользователя: {userData}</div>
      {isAdmin && <AdminPart />} {/* Условный рендер целого компонента */}
    </div>
  );
}
  • Используйте хуки, возвращающие null или пустые значения в своих результатах при невыполнении условия:
function useConditionalHook(condition) {
  const [data, setData] = useState(null);
  useEffect(() => {
    if (condition) {
      // Выполняем эффект только если condition true
    }
  }, [condition]);
  return condition ? data : null;
}

Итог

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

Почему нельзя использовать хуки внутри условного рендеринга? | PrepBro