Кастомные хуки позволяют инкапсулировать сложную логику взаимодействия с элементами интерфейса и переиспользовать её в разных компонентах. В контексте React Aria кастомные хуки часто создаются для управления состоянием, обработки событий и обеспечения доступности через ARIA-атрибуты.
Ключевое преимущество кастомного хука — возможность отделить логику от представления. В React Aria это особенно важно, так как библиотека предоставляет примитивы для доступности, но не диктует визуальное оформление.
Типичный кастомный хук в React Aria включает следующие элементы:
import { useButton } from '@react-aria/button';
import { useFocusRing } from '@react-aria/focus';
import { mergeProps } from '@react-aria/utils';
import { useState } from 'react';
function useCustomToggle(initialState = false) {
const [isToggled, setToggled] = useState(initialState);
const toggle = () => setToggled(prev => !prev);
return { isToggled, toggle };
}
Состояние управляет логикой поведения элемента, отделяя её от UI-компонента.
function useAccessibleButton(props) {
const ref = React.useRef();
const { buttonProps } = useButton(props, ref);
const { isFocusVisible, focusProps } = useFocusRing();
return {
ref,
props: mergeProps(buttonProps, focusProps),
isFocusVisible
};
}
Здесь mergeProps объединяет стандартные свойства кнопки с логикой фокуса, гарантируя корректное управление доступностью.
Создание toggle-кнопки с поддержкой клавиатуры и ARIA:
import { useButton } from '@react-aria/button';
import { useFocusRing } from '@react-aria/focus';
import { mergeProps } from '@react-aria/utils';
import { useState, useRef } from 'react';
function useToggleButton(initialState = false, onChange) {
const [isSelected, setSelected] = useState(initialState);
const ref = useRef();
const handleToggle = () => {
setSelected(prev => !prev);
if (onChange) onChange(!isSelected);
};
const { buttonProps } = useButton({ onPress: handleToggle, 'aria-pressed': isSelected }, ref);
const { isFocusVisible, focusProps } = useFocusRing();
return {
ref,
props: mergeProps(buttonProps, focusProps),
isSelected,
isFocusVisible
};
}
Использование хука в компоненте:
function ToggleButton() {
const { ref, props, isSelected, isFocusVisible } = useToggleButton(false, (state) => console.log(state));
return (
<button ref={ref} {...props} style={{ border: isFocusVisible ? '2px solid blue' : '1px solid gray' }}>
{isSelected ? 'Вкл' : 'Выкл'}
</button>
);
}
useButton,
useCheckbox, useMenu и другие позволяют
автоматически генерировать корректные атрибуты.mergeProps
безопасно комбинирует несколько наборов свойств, предотвращая конфликты
событий.useFocusRing
помогает визуализировать доступность через клавиатуру и поддерживает
стандарты WCAG.Кастомные хуки React Aria часто управляют сложными состояниями, например:
Пример: хук для управления состоянием меню:
import { useMenuTriggerState } from '@react-stately/menu';
import { useMenuTrigger } from '@react-aria/menu';
function useCustomMenu() {
const state = useMenuTriggerState();
const ref = useRef();
const { menuTriggerProps, menuProps } = useMenuTrigger({}, state, ref);
return { ref, state, menuTriggerProps, menuProps };
}
Такой подход разделяет логическое состояние меню (открыто/закрыто, выбранный элемент) и поведение интерфейса, что упрощает поддержку и тестирование.
mergeProps.ref, props, состоянием и
флагами фокуса.Такой подход гарантирует чистый, переиспользуемый и доступный код, полностью совместимый с экосистемой React Aria.