webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
React · Урок 4 из 7

Свои хуки

Переиспользуемая логика, правила хуков, useSyncExternalStore.

Обновлено

Что такое хук

Хук — особая функция React (имя начинается с use), которая даёт компоненту доступ к возможностям React: памяти (useState), эффектам (useEffect), контексту (useContext) и т. д.

Свой хук — функция, которую пишете вы и которая использует другие хуки: так логику с состоянием выносят и переиспользуют в нескольких компонентах.

function useToggle(initial = false) {
  const [on, setOn] = useState(initial)
  const toggle = useCallback(() => setOn(v => !v), [])
  return [on, toggle] as const
}

const [menuOpen, toggleMenu] = useToggle()
const [darkMode, toggleDark] = useToggle(true)   // полностью отдельное состояние

Важно: свой хук разделяет логику, а не состояние. У каждого компонента, который его вызывает, своя копия.

Правила хуков

  1. Вызывайте хуки только на верхнем уровне компонента или другого хука — не в if, циклах или колбэках.
  2. Только из React-компонентов или других хуков — не из обычных функций.

Почему: React различает хуки по порядку вызовов при каждом рендере. if, который пропускает хук, сбивает порядок, и состояние попадает не в тот хук.

Хуки React — по категориям

Категория Хуки Для
состояние useState, useReducer память компонента
контекст useContext, use(Context) общие данные без props
эффекты useEffect, useLayoutEffect синхронизация с внешним миром
ссылки useRef DOM и значения без перерисовки
производительность useMemo, useCallback мемоизация (React Compiler делает её автоматически)
внешние источники useSyncExternalStore подписка на сторы, media queries, localStorage
действия (React 19) useActionState, useOptimistic, useFormStatus, useTransition формы, мутации, оптимистичный UI
асинхронные данные use(promise) чтение Promise с Suspense

Примеры, которые пригодятся в любом проекте

function useDebouncedValue<T>(value: T, delay = 300) {
  const [debounced, setDebounced] = useState(value)
  useEffect(() => {
    const id = setTimeout(() => setDebounced(value), delay)
    return () => clearTimeout(id)
  }, [value, delay])
  return debounced
}

function useMediaQuery(query: string) {
  return useSyncExternalStore(
    cb => {
      const m = matchMedia(query)
      m.addEventListener('change', cb)
      return () => m.removeEventListener('change', cb)
    },
    () => matchMedia(query).matches,
    () => false,                       // значение на сервере
  )
}

useSyncExternalStore — правильный способ подписаться на внешний источник; именно так редактор кода в этом приложении определяет светлую/тёмную тему.

Когда выносить свой хук

Признак Пример
одна и та же связка useState + useEffect в 2+ компонентах debounce, fetch, media query
в компоненте много логики и мало JSX useCheckout() забирает логику, компонент остаётся просто UI
хотите тестировать логику отдельно хук тестируется через renderHook

Не выносите хуки «потому что можно» — хук на 3 строки, используемый один раз, только прячет код.

Где они лежат в FSD

Хук, связанный с сущностью → entities/<x>/model/use-x.ts. Общий хук (debounce, media query) → shared/lib/.

Коротко

  • Свой хук = функция use..., которая собирает другие хуки; разделяет логику, а не состояние.
  • Только на верхнем уровне, всегда в одном порядке.
  • useSyncExternalStore — для внешних источников; выносите хуки, когда логика повторяется.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.