Почему хуки нельзя вызывать внутри условий и как это связано с жизненным циклом React-компонента
Что проверяют
Понимаете ли вы, что React связывает вызов хука с его состоянием по порядку, а не по имени переменной. Правило простое, но ответ «так написано в документации» показывает, что внутреннего устройства кандидат не знает.
Как отвечать
У каждого смонтированного компонента есть список ячеек состояния, привязанный к его узлу дерева. На каждом рендере React идёт по этому списку указателем: первый вызов хука забирает первую ячейку, второй вторую, и так далее. Имя переменной, в которую вы кладёте результат, движку недоступно вовсе.
Если хук стоит под условием, то при смене условия сдвигается вся нумерация. Состояние, принадлежавшее одному useState, достанется другому, эффект получит чужие зависимости, а если хуков стало меньше, React упадёт с сообщением о том, что их отрендерилось меньше ожидаемого.
Связь с жизненным циклом прямая: ячейки живут, пока компонент смонтирован, а сопоставление устанавливается заново на каждом рендере и обязано совпасть с предыдущим. Ранний return до хуков ломает ровно то же самое.
Правильный приём: условие переносится внутрь хука, а не оборачивает его.
useEffect(() => {
if (!enabled) return;
return subscribe(id);
}, [enabled, id]);Если веткам нужен разный набор хуков, ветка выносится в отдельный компонент и условно рендерится уже он. Нарушения ловит плагин eslint-plugin-react-hooks, и его предупреждения игнорировать нельзя.
Где спотыкаются
Объясняют через «React так устроен» и не могут сказать, что именно внутри. Вопрос как раз про механизм: соответствие ячеек по порядку вызова.
Считают цикл безопасным, если итераций фиксированное число. Пока длина массива постоянна, это случайно работает, но первый рендер с другой длиной сдвигает всё. Правило про одинаковый порядок при каждом рендере, а не про константу в коде.
Забывают про ранний выход. Строка if (!user) return null; перед useEffect нарушает правило так же, как условие вокруг хука, и выстреливает ровно тогда, когда user наконец появится.