Кастомные хуки вглубь
Урок про кастомные хуки вглубь: как выносить логику из компонентов и компоновать хуки друг из друга, не нарушая правил хуков.
Кастомный хук — это функция с именем на
use…, которая вызывает другие хуки и инкапсулирует кусок логики с состоянием, переиспользуемый между компонентами.
Что кастомный хук на самом деле делает
Кастомный хук — не магия и не «общее состояние». Это просто способ вынести вызовы useState/useEffect/useMemo в отдельную функцию. Каждый компонент, вызвавший хук, получает свой собственный, независимый экземпляр этого состояния. Хук переиспользует логику, а не данные.
function useToggle(initial = false) {
const [on, setOn] = React.useState(initial);
const toggle = React.useCallback(() => setOn((v) => !v), []);
return [on, toggle];
}
// использование — у каждого свой независимый стейт
function Panel() {
const [open, toggleOpen] = useToggle();
return <button onClick={toggleOpen}>{open ? "Скрыть" : "Показать"}</button>;
}
Зачем выделять
- Переиспользование логики без копипаста: подписки, дебаунс, загрузка данных, формы.
- Читаемость компонента: тело компонента становится «что показать», а не «как посчитать».
- Тестируемость: логику хука проще тестировать отдельно от вёрстки.
Композиция хуков
Хуки складываются как функции. Кастомный хук может вызывать другие кастомные хуки. Соберём useDebouncedValue и используем его внутри useSearch.
function useDebouncedValue(value, delay) {
const [debounced, setDebounced] = React.useState(value);
React.useEffect(() => {
const id = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(id);
}, [value, delay]);
return debounced;
}
function useSearch(query) {
const debounced = useDebouncedValue(query, 300);
const [results, setResults] = React.useState([]);
React.useEffect(() => {
if (!debounced) return;
fetchResults(debounced).then(setResults);
}, [debounced]);
return results;
}
Так строится «лесенка» абстракций: низкоуровневый хук решает одну задачу (дебаунс), верхний — компонует его с загрузкой. Компонент остаётся чистым.
Правила, которые нельзя нарушать
- Вызывайте хуки только на верхнем уровне функции — не в условиях, циклах или вложенных функциях. React опирается на порядок вызовов между рендерами.
- Вызывайте хуки только из React-компонентов или из других хуков. Имя обязано начинаться с
use— по нему линтер проверяет правила. - Указывайте все внешние значения в массиве зависимостей
useEffect/useMemo/useCallback— иначе получите «залипшее» (stale) значение.
Когда НЕ стоит делать хук
Если логика используется в одном месте и не содержит состояния/эффектов — это просто обычная функция, а не хук. Не превращайте чистую функцию formatPrice(n) в useFormatPrice — лишний use только обманет линтер и читателя.
Итог
- Кастомный хук переиспользует логику; состояние у каждого вызова своё.
- Хуки компонуются: одни кастомные хуки строятся из других.
- Соблюдайте правила хуков: верхний уровень, имя на
use, полные зависимости. - Без состояния и эффектов — делайте обычную функцию, а не хук.