В библиотеке React Aria взаимодействие между хуками является ключевым механизмом для построения доступных интерфейсов. React Aria предоставляет хуки, которые инкапсулируют поведение компонентов, разделяя управление состоянием, доступность и логику событий. Понимание того, как эти хуки взаимодействуют, позволяет создавать гибкие и масштабируемые компоненты.
React Aria разделяет состояние компонента и поведение компонента на разные уровни:
useToggleState,
useComboBoxState, useListState) отвечают за
хранение и обновление состояния компонента. Они не знают о DOM и не
взаимодействуют с событиями напрямую.useButton,
useCheckbox, useComboBox) предоставляют
обработчики событий, атрибуты ARIA и привязки к DOM. Они используют
состояние из хуков состояния и преобразуют его в доступное
поведение.Такое разделение позволяет декорировать один и тот же компонент разными поведениями без дублирования логики.
Хуки поведения обычно принимают объект состояния как аргумент:
import { useButton } from "@react-aria/button";
import { useToggleState } from "@react-stately/toggle";
function ToggleButton(props) {
const state = useToggleState(props);
const { buttonProps } = useButton(props, state);
return <button {...buttonProps}>{state.isSelected ? "Вкл" : "Выкл"}</button>;
}
useToggleState управляет булевым состоянием
isSelected.useButton использует это состояние для назначения
правильных атрибутов ARIA (aria-pressed) и обработчиков
событий (onClick).Ключевой момент: хуки поведения не изменяют состояние напрямую; они лишь уведомляют состояние о действиях пользователя.
В сложных компонентах часто требуется объединение нескольких хуков
поведения. Например, комбинированный компонент
CheckboxGroup может использовать одновременно
useCheckboxGroupState и useCheckbox:
import { useCheckboxGroupState } from "@react-stately/checkbox";
import { useCheckbox } from "@react-aria/checkbox";
function CheckboxItem({ value, state }) {
const { inputProps } = useCheckbox({ value }, state);
return <input {...inputProps} />;
}
function CheckboxGroup({ options }) {
const state = useCheckboxGroupState({ value: [], onChange: () => {} });
return options.map(option => (
<CheckboxItem key={option} value={option} state={state} />
));
}
useCheckboxGroupState
отслеживает выбранные элементы.useCheckbox использует
это состояние для генерации корректных ARIA-атрибутов и
обработчиков.Это позволяет создавать групповые компоненты без нарушения доступности.
React Aria активно использует колбеки и события для координации между хуками:
onChange, onFocus, onBlur
передаются из поведения в состояние.state.toggle() или
state.setSelectedKeys().Пример передачи событий между хуками:
function ComboBox({ items }) {
const state = useComboBoxState({ items });
const { inputProps, listBoxProps } = useComboBox({ inputRef: inputRef }, state);
return (
<>
<input {...inputProps} ref={inputRef} />
<ul {...listBoxProps}>
{state.collection.map(item => (
<li key={item.key}>{item.rendered}</li>
))}
</ul>
</>
);
}
Здесь useComboBox использует состояние
state для управления открытием списка, выделением элемента
и обработкой клавиатуры.
Многие хуки поведения требуют рефы на DOM-элементы. Правильное управление рефами критично для синхронизации:
useButton или useCheckbox принимает
ref, который указывает на DOM-элемент.Пример:
const MyButton = React.forwardRef((props, ref) => {
const { buttonProps } = useButton(props, ref);
return <button {...buttonProps} ref={ref}>{props.children}</button>;
});
В больших приложениях может возникнуть необходимость синхронизации нескольких состояний между хуками. React Aria решает это через:
Context, что позволяет синхронизировать
состояние группы компонентов.onChange и эффекты —
обновление внешнего состояния при изменении внутреннего, создавая
реактивную цепочку между хуками.Пример с контекстом:
const ListContext = React.createContext();
function ListProvider({ children }) {
const state = useListState({ items: ["A", "B", "C"] });
return <ListContext.Provider value={state}>{children}</ListContext.Provider>;
}
function ListItem({ key }) {
const state = React.useContext(ListContext);
return <div>{state.collection.getItem(key).rendered}</div>;
}
Эта архитектура делает компоненты React Aria модульными, предсказуемыми и доступными, позволяя создавать сложные интерфейсы без дублирования логики и с полной поддержкой ARIA.