Кастомные хуки
Учимся выносить логику с состоянием в собственные хуки, чтобы переиспользовать её между компонентами.
Кастомный хук — обычная функция, имя которой начинается с
useи которая внутри использует встроенные хуки React, чтобы инкапсулировать переиспользуемую логику.
Зачем нужны кастомные хуки
Компоненты переиспользуют разметку. А как переиспользовать логику — например, «загрузить данные», «следить за шириной окна», «работать с localStorage»? Копировать useState + useEffect из компонента в компонент — плохо. Эту логику выносят в кастомный хук.
Пример: useToggle
Часто нужно переключаемое булево состояние (модалка открыта/закрыта). Вынесем это:
import { useState } from "react";
function useToggle(initial = false) {
const [value, setValue] = useState(initial);
const toggle = () => setValue((v) => !v);
return [value, toggle];
}
Теперь любой компонент использует это в одну строку:
function Modal() {
const [isOpen, toggle] = useToggle(false);
return (
<div>
<button onClick={toggle}>
{isOpen ? "Закрыть" : "Открыть"}
</button>
{isOpen && <p>Содержимое окна</p>}
</div>
);
}
Пример: useFetch
Логику загрузки из раздела про эффекты тоже легко обобщить в хук:
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(url)
.then((r) => r.json())
.then(setData)
.finally(() => setLoading(false));
}, [url]);
return { data, loading };
}
И применение в любом компоненте:
function Profile({ id }) {
const { data, loading } = useFetch(`/api/users/${id}`);
if (loading) return <p>Загрузка...</p>;
return <h1>{data.name}</h1>;
}
Два правила кастомных хуков
- Имя начинается с
use— по нему React и линтер понимают, что внутри работают хуки, и проверяют правила. - Внутри действуют те же правила хуков — вызывать встроенные хуки только на верхнем уровне функции.
Важно: состояние не разделяется
Распространённое заблуждение: будто два компонента, использующих один хук, делят состояние. Это не так — каждый вызов хука создаёт собственное независимое состояние. Хук переиспользует логику, а не данные. Если два компонента вызвали useToggle, у каждого свой isOpen.
Итог
- Кастомный хук выносит логику с состоянием/эффектами в функцию с именем на
use. - Внутри действуют обычные правила хуков; хук возвращает то, что нужно компоненту (значения, функции).
- Каждый вызов хука имеет своё независимое состояние — переиспользуется логика, а не данные.