В React Aria меню управляется через контролируемое
состояние, которое отделено от визуального отображения
компонентов. Основная идея — использовать
useMenuTriggerState для управления открытием и закрытием
меню, что позволяет интегрировать клавиатурные и мышиные события без
необходимости ручного отслеживания каждого события.
import { useMenuTriggerState } from "@react-stately/menu";
let state = useMenuTriggerState({});
Ключевые свойства состояния:
isOpen — булево значение, указывающее, открыто меню или
закрыто.open() — функция для открытия меню.close() — функция для закрытия меню.toggle() — переключение состояния меню.Это состояние легко комбинируется с обработчиками событий на кнопке-триггере меню.
Для стандартной кнопки-триггера используется хук
useMenuTrigger из React Aria. Он предоставляет необходимые
атрибуты для кнопки и связанного меню:
import { useMenuTrigger } from "@react-aria/menu";
let { menuTriggerProps, menuProps } = useMenuTrigger({ type: 'menu' }, state);
Особенности работы с закрытием:
useOverlay.Для корректной работы важно передавать menuProps на
компонент меню, чтобы React Aria мог корректно обработать события
закрытия.
useOverlay для управления закрытиемuseOverlay обеспечивает универсальное управление
закрытием модальных элементов, включая меню. При интеграции с меню это
позволяет реагировать на:
Пример использования:
import { useOverlay } from "@react-aria/overlays";
let { overlayProps } = useOverlay(
{
onClose: state.close,
isOpen: state.isOpen,
isDismissable: true
},
menuRef
);
overlayProps следует передавать на корневой элемент меню
для корректной обработки закрытия.
При выборе пункта меню часто требуется автоматически закрывать меню.
React Aria обеспечивает это через вызов state.close()
внутри обработчика выбора:
function MenuItem({ item }) {
let onSel ect = () => {
console.log(`Выбран элемент: ${item.name}`);
state.close();
};
return <div onCl ick={onSelect}>{item.name}</div>;
}
Для комплексных меню с вложенными подменю закрытие может быть частичным — закрываются только дочерние подменю, в то время как родительское остаётся открытым.
React Aria автоматически обеспечивает закрытие меню через клавиши:
Ключевое преимущество React Aria — это автоматическое связывание этих
действий с состоянием меню через useMenuTriggerState, без
необходимости писать отдельную логику для каждого события
клавиатуры.
import React, { useRef } from "react";
import { useMenuTriggerState } from "@react-stately/menu";
import { useMenuTrigger, useMenu } from "@react-aria/menu";
import { useOverlay } from "@react-aria/overlays";
function DropdownMenu({ items }) {
let state = useMenuTriggerState({});
let triggerRef = useRef();
let menuRef = useRef();
let { menuTriggerProps, menuProps } = useMenuTrigger({ type: "menu" }, state);
let { overlayProps } = useOverlay(
{ onClose: state.close, isOpen: state.isOpen, isDismissable: true },
menuRef
);
return (
<>
<button {...menuTriggerProps} ref={triggerRef}>Меню</button>
{state.isOpen && (
<ul {...menuProps} {...overlayProps} ref={menuRef}>
{items.map(item => (
<li key={item.key} onCl ick={() => state.close()}>
{item.name}
</li>
))}
</ul>
)}
</>
);
}
Особенности:
state.useOverlay.isDismissable: true в
useOverlay для корректного закрытия при кликах вне
меню.menuProps и overlayProps после изменения
списка элементов.state.isOpen для рендеринга и скрытия компонентов.Такой подход обеспечивает согласованное и предсказуемое закрытие меню во всех сценариях, включая клики, клавиатуру и вложенные структуры.