Можно ли использовать хуки внутри условия?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Почему нельзя использовать хуки внутри условий в React
Нет, использовать хуки React (такие как useState, useEffect, useContext и другие) внутри условий, циклов или вложенных функций категорически нельзя. Это фундаментальное правило, которое React строго требует соблюдать при работе с хуками. Нарушение этого правила приведёт к ошибке с сообщением "React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render." в консоли разработчика.
Основная причина: Гарантия порядка вызова хуков
React полагается на строгий и стабильный порядок вызова хуков между рендерами одного и того же компонента. Внутри React для каждого компонента ведётся внутренний список (или очередь) "ячеек памяти" (memory cells), которые хранят состояние хуков.
// ❌ НЕПРАВИЛЬНО: хук вызывается внутри условия
function MyComponent({ shouldUseCounter }) {
if (shouldUseCounter) {
const [count, setCount] = useState(0); // Хук может быть не вызван!
// ...
}
const [name, setName] = useState(''); // Порядок нарушен
}
// ✅ ПРАВИЛЬНО: хуки всегда вызываются в одинаковом порядке
function MyComponent({ shouldUseCounter }) {
const [count, setCount] = useState(0); // Всегда первым
const [name, setName] = useState(''); // Всегда вторым
const counterLogic = shouldUseCounter ? count : null;
// ... или используйте другой хук
const enabledState = useState(null);
const stateToUse = shouldUseCounter ? count : enabledState[0];
}
На каждом рендере React проходит по этому списку ячеек по порядку. Если в одном рендере хук был вызван первым, а в следующем — вторым (из-за сработавшего условия if), React "перепутает" состояние между хуками. Например, значение useState для счётчика может быть ошибочно присвоено переменной имени, что приведёт к непредсказуемым багам и крашу приложения.
Как правильно организовать условную логику с хуками
Существует несколько паттернов, позволяющих соблюсти правило хуков, сохранив нужную функциональность:
1. Выносите условие ВНУТРЬ хука
Используйте условную логику внутри эффектов или других хуков, а не вокруг их вызова.
function MyComponent({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
// Условие внутри хука useEffect - правильно
if (userId) {
fetchUser(userId).then(setUser);
}
}, [userId]);
}
2. Разделяйте компоненты
Если логика сильно различается, разделите компонент на два, используя условный рендеринг на уровне выше.
function UserProfile({ user }) {
return user ? <AuthenticatedView user={user} /> : <GuestView />;
}
function AuthenticatedView({ user }) {
// Все хуки вызываются в стабильном порядке
const [settings, setSettings] = useState(null);
useEffect(() => { /* ... */ }, [user.id]);
return <div>Hello, {user.name}</div>;
}
function GuestView() {
const [guestId, setGuestId] = useState(generateId());
return <div>Welcome, guest #{guestId}</div>;
}
3. Используйте хук useMemo или useCallback для условных вычислений
Для условной зависимости мемоизированных значений или функций применяйте хуки до условия, а логику размещайте внутри них.
function MyComponent({ heavyData, isEnabled }) {
// Хук useMemo вызывается всегда
const processedData = useMemo(() => {
// Условие внутри useMemo
return isEnabled ? expensiveTransform(heavyData) : null;
}, [heavyData, isEnabled]); // Зависимости включают условие
}
Исключение из правила: Пользовательские хуки
Пользовательские хуки (custom hooks) также должны соблюдать это правило. Однако вы можете использовать условия внутри тела пользовательского хука, если сами вызовы хуков React внутри него остаются в неизменном порядке.
// ✅ ПРАВИЛЬНО: внутри кастомного хука условная логика допустима,
// если порядок встроенных хуков не нарушен
function useCustomHook(shouldFetch) {
const [data, setData] = useState(null);
// Условие НЕ вокруг useState или useEffect
useEffect(() => {
if (shouldFetch) { // Условие внутри хука - нормально
fetchData().then(setData);
}
}, [shouldFetch]);
return data;
}
Что происходит технически при нарушении?
React использует индекс текущего обрабатываемого хука, который увеличивается с каждым вызовом хука в компоненте. При сбое порядка React не сможет сопоставить текущий вызов с правильной ячейкой памяти, что ведёт к:
- Смешиванию состояний разных хуков.
- Потере актуального значения состояния.
- Ошибкам выполнения в последующих рендерах.
Вывод
Правило "Не вызывайте хуки внутри условий" — это не просто рекомендация по стилю, а критическое требование для корректной работы механизма состояния и жизненного цикла React. Соблюдение этого правила гарантирует, что React сможет однозначно связать каждый вызов хука с конкретной ячейкой памяти между рендерами. Всегда используйте альтернативные подходы: условия внутри хуков, разделение компонентов или условный рендеринг, чтобы ваше приложение оставалось стабильным и предсказуемым.