useHover для наведения

useHover — это хук из библиотеки React Aria, предназначенный для управления состоянием наведения (hover) на элементах интерфейса с учётом доступности. Он автоматически обеспечивает корректное поведение как для мыши, так и для сенсорных устройств, избегая ложных срабатываний и поддерживая взаимодействие с клавиатурой и вспомогательными технологиями.


Импорт и базовое применение

Для начала работы useHover импортируется напрямую из пакета:

import { useHover } from '@react-aria/interactions';

Простейший пример использования:

import { useHover } from '@react-aria/interactions';
import { useRef } from 'react';

function HoverButton() {
  const ref = useRef();
  const { hoverProps, isHovered } = useHover({});

  return (
    <button
      {...hoverProps}
      ref={ref}
      style={{
        backgroundColor: isHovered ? 'lightblue' : 'white',
        transition: 'background-color 0.2s ease'
      }}
    >
      Наведи на меня
    </button>
  );
}

Ключевые моменты:

  • hoverProps — набор пропсов, которые нужно передать элементу, чтобы useHover корректно отслеживал события наведения.
  • isHovered — булевое значение, указывающее, находится ли курсор мыши над элементом.
  • Хук работает с любыми элементами, не ограничиваясь кнопками или ссылками.

Настройка поведения с isDisabled

useHover поддерживает опцию isDisabled, которая отключает отслеживание наведения:

const { hoverProps, isHovered } = useHover({ isDisabled: true });

В этом случае hoverProps не будут реагировать на события мыши и сенсора. Это полезно для условного взаимодействия, например, когда элемент временно неактивен.


Работа с сенсорными устройствами

На сенсорных устройствах хук корректно определяет касания, предотвращая ложные состояния наведения, которые часто возникают при имитации мыши на мобильных устройствах. React Aria автоматически отключает hover для элементов, где взаимодействие через сенсор подразумевает клик или свайп, что повышает точность интерфейса.


Сочетание с другими хуками React Aria

useHover можно безопасно комбинировать с другими хуками из @react-aria/interactions, такими как usePress или useFocusRing. Например, для кнопки с наведением и фокусом:

import { useHover, useFocusRing, usePress } from '@react-aria/interactions';
import { useRef } from 'react';

function InteractiveButton() {
  const ref = useRef();
  const { hoverProps, isHovered } = useHover({});
  const { focusProps, isFocusVisible } = useFocusRing();
  const { pressProps, isPressed } = usePress({});

  return (
    <button
      {...hoverProps}
      {...focusProps}
      {...pressProps}
      ref={ref}
      style={{
        backgroundColor: isPressed
          ? 'darkblue'
          : isHovered
          ? 'lightblue'
          : 'white',
        outline: isFocusVisible ? '2px solid orange' : 'none',
        transition: 'all 0.2s ease'
      }}
    >
      Интерактивная кнопка
    </button>
  );
}

Особенности:

  • useFocusRing обеспечивает видимую подсветку при фокусе клавиатурой.
  • usePress добавляет состояние нажатия.
  • Все хуки объединяются, не конфликтуя, что гарантирует корректное поведение на разных устройствах и способах взаимодействия.

Расширенные возможности: callbacks onHoverStart и onHoverEnd

Хук поддерживает обработчики начала и окончания наведения:

const { hoverProps } = useHover({
  onHoverStart: () => console.log('Наведение началось'),
  onHoverEnd: () => console.log('Наведение завершилось')
});

Эти callbacks позволяют запускать анимации, логировать события или динамически изменять состояние приложения при наведении. Использование их предпочтительно перед прямым наблюдением isHovered в useEffect, так как они учитывают внутренние механизмы React Aria и оптимизированы под разные платформы.


Интеграция с компонентами кастомного UI

useHover идеально подходит для создания кастомных компонентов, например, тултипов или всплывающих меню:

function Tooltip({ children, label }) {
  const ref = useRef();
  const { hoverProps, isHovered } = useHover({});

  return (
    <div style={{ display: 'inline-block', position: 'relative' }} {...hoverProps} ref={ref}>
      {children}
      {isHovered && (
        <div style={{
          position: 'absolute',
          bottom: '100%',
          left: '50%',
          transform: 'translateX(-50%)',
          padding: '4px 8px',
          backgroundColor: 'black',
          color: 'white',
          borderRadius: '4px',
          whiteSpace: 'nowrap'
        }}>
          {label}
        </div>
      )}
    </div>
  );
}

Преимущества подхода:

  • Tooltip появляется только при активном наведении.
  • React Aria обеспечивает корректное скрытие тултипа на мобильных устройствах.
  • Простая интеграция с любыми элементами интерфейса без дополнительной логики управления событиями.

Практические рекомендации

  • Для плавных визуальных эффектов использовать CSS-переходы вместе с состоянием isHovered.
  • Обязательно применять ref к элементу, так как React Aria отслеживает события через реальный DOM-узел.
  • Совмещать с другими хуками взаимодействия (usePress, useFocusRing) для комплексных UI-компонентов.
  • Использовать callbacks onHoverStart и onHoverEnd для оптимизированного реагирования на наведение, особенно при сложных анимациях или сетевых запросах.

useHover обеспечивает универсальный, доступный и кросс-платформенный способ управления наведением в React-приложениях, позволяя создавать интерфейсы, корректно работающие на мыши, клавиатуре и сенсорных устройствах.