Правила использования React хуков: как писать код без ошибок
8 апреля 2026 г.
React хуки появились в версии 16.8 и позволили использовать состояние и другие возможности React без написания классов. Однако хуки работают не как обычные функции — у них есть строгие правила. Нарушение этих правил приводит к трудноуловимым багам и нестабильной работе приложения. В этой статье разберём два главных правила использования хуков, почему они существуют и как их соблюдать на практике.
Два главных правила React хуков
Официальная документация React формулирует два обязательных правила для всех хуков (useState, useEffect, useContext, useReducer и других):
- Вызывайте хуки только на верхнем уровне.
- Вызывайте хуки только из React-функций.
Рассмотрим каждое правило подробнее.
1. Вызов только на верхнем уровне
Не вызывайте хуки внутри циклов, условий или вложенных функций. Хуки должны вызываться в одном и том же порядке при каждом рендере компонента. Только так React может правильно сохранять состояние между множественными вызовами useState и useEffect.
❌ Неправильно:
function MyComponent({ items }) {
if (items.length === 0) {
const [isEmpty, setIsEmpty] = useState(true); // Ошибка!
}
for (let i = 0; i < items.length; i++) {
const [itemState, setItemState] = useState(null); // Ошибка!
}
return <div>...</div>;
}
✅ Правильно:
function MyComponent({ items }) {
const [isEmpty, setIsEmpty] = useState(items.length === 0);
// Если нужно состояние для каждого элемента — используй useReducer или один объект
const [itemsState, setItemsState] = useState(() =>
items.map(() => null)
);
return <div>...</div>;
}
2. Вызов только в React-функциях
Не вызывайте хуки в обычных JavaScript-функциях. Есть только два места, где хуки разрешены:
- В функциональных компонентах React.
- В кастомных хуках (функциях, имя которых начинается с
use, напримерuseWindowWidth).
❌ Неправильно:
function formatUserData(user) {
const [data, setData] = useState(user); // Ошибка!
return data.toUpperCase();
}
function MyComponent() {
return <div>{formatUserData(user)}</div>;
}
✅ Правильно:
function useFormattedUser(user) {
const [data, setData] = useState(user);
useEffect(() => {
setData(user.toUpperCase());
}, [user]);
return data;
}
function MyComponent({ user }) {
const formattedUser = useFormattedUser(user);
return <div>{formattedUser}</div>;
}
Почему эти правила так важны?
React опирается на порядок вызова хуков, чтобы правильно связывать каждое состояние с соответствующим хуком. Внутри React каждый хук в компоненте получает индекс — по порядку их вызова. При следующем рендере React ожидает, что хуки будут вызваны в той же последовательности.
Если ты поместишь хук внутрь условия, порядок может нарушиться. Например, при первом рендере условие истинно и хук вызывается, а при втором — ложно, и хук пропускается. Тогда React не сможет сопоставить сохранённое состояние с правильным хуком, и данные «съедут» — состояние одного хука попадёт в другой.
Та же логика работает для циклов: количество вызовов хуков должно быть одинаковым при каждом рендере. Если массив items изменит длину, количество вызовов хуков изменится, и React сломается.
Распространённые ошибки и как их избежать
Ошибка 1: условный вызов useEffect или useState
Вместо условия вокруг хука используй условие внутри хука.
// ❌ Плохо
if (isVisible) {
useEffect(() => {
console.log('Visible');
}, [isVisible]);
}
// ✅ Хорошо
useEffect(() => {
if (isVisible) {
console.log('Visible');
}
}, [isVisible]);
Ошибка 2: вызов хука в обработчике события
Обработчики событий не являются React-функциями и не вызываются при каждом рендере.
// ❌ Плохо
function Button() {
const handleClick = () => {
const [clicked, setClicked] = useState(false); // Ошибка!
setClicked(true);
};
return <button onClick={handleClick}>Click</button>;
}
// ✅ Хорошо
function Button() {
const [clicked, setClicked] = useState(false);
const handleClick = () => setClicked(true);
return <button onClick={handleClick}>Click</button>;
}
Ошибка 3: хук внутри useMemo или useCallback
Эти функции тоже не гарантируют стабильный порядок вызова.
// ❌ Плохо
const memoized = useMemo(() => {
const [value, setValue] = useState(0); // Ошибка!
return value;
}, []);
// ✅ Хорошо — подними хук наверх
const [value, setValue] = useState(0);
const memoized = useMemo(() => value, [value]);
Как ESLint помогает соблюдать правила
React предоставляет официальный плагин eslint-plugin-react-hooks, который автоматически проверяет соблюдение правил хуков. Он найдёт вызовы внутри условий, циклов или обычных функций.
Установка и настройка:
npm install eslint-plugin-react-hooks --save-dev
В файле .eslintrc.js:
module.exports = {
plugins: ['react-hooks'],
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
}
};
Правило exhaustive-deps предупреждает о пропущенных зависимостях в useEffect, useMemo и useCallback — это необязательное, но крайне полезное дополнение.
Итог
Два правила использования React хуков — это не просто рекомендации, а обязательные условия для корректной работы React. Запомни:
- Вызывай хуки всегда на верхнем уровне компонента или кастомного хука — не внутри условий, циклов или вложенных функций.
- Вызывай хуки только из функциональных компонентов React или кастомных хуков (с префиксом
use). - Используй
eslint-plugin-react-hooks, чтобы не пропустить нарушение.
Соблюдение этих правил сделает твой код предсказуемым, а состояние компонентов — стабильным. Если ты только начинаешь работать с хуками, настрой линтер сразу — это сэкономит часы отладки в будущем.
Что почитать дальше
Дополнительные материалы из архива, которые могут быть полезны после этой статьи.
Настройка ESLint для React приложения: полное руководство
Пошаговое руководство по настройке ESLint в React-проектах. Установка, конфигурация, популярные плагины, интеграция с I…
Читать далее
Самые популярные вопросы по Next.js на собеседовании: разбор с примерами
Собрали 30+ самых частых вопросов по Next.js для подготовки к собеседованию. Разбираем App Router, Server Components, р…
Читать далее
Самые популярные вопросы по React на собеседовании: разбор с примерами
Готовишься к собеседованию по React? Мы собрали 30+ самых частых вопросов с развернутыми ответами и примерами кода: хук…
Читать далее