В React Aria управление рефами играет ключевую роль для создания доступных компонентов, обеспечивая корректную работу с фокусом, скринридерами и другими ассистивными технологиями. Рефы позволяют напрямую обращаться к DOM-элементам, управлять их состоянием и интегрироваться с библиотекой React Aria для соблюдения WAI-ARIA стандартов.
React Aria поддерживает несколько способов управления рефами:
React Ref Стандартный способ создания ссылок на
DOM-элементы через React.useRef():
import {useRef} from 'react';
const inputRef = useRef(null);
<input ref={inputRef} />
Такой реф хранит ссылку на реальный DOM-элемент и позволяет выполнять
методы вроде focus() или
scrollIntoView().
Forwarded Ref Для передачи рефа через компоненты
используется React.forwardRef. Это особенно важно для
оберток, когда внутренний элемент должен быть доступен родителю:
import React, {forwardRef} from 'react';
const Button = forwardRef((props, ref) => (
<button ref={ref} {...props} />
));
const App = () => {
const buttonRef = useRef(null);
return <Button ref={buttonRef}>Click me</Button>;
};React Aria Ref В React Aria часто используется
специальная функция mergeRefs, позволяющая комбинировать
несколько рефов в один. Это необходимо, когда библиотека требует свой
реф для внутренней логики, но компонент также должен принимать
пользовательский реф:
import {mergeRefs} from '@react-aria/utils';
import {useRef} from 'react';
const internalRef = useRef(null);
const externalRef = useRef(null);
<input ref={mergeRefs(internalRef, externalRef)} />Рефы в React Aria тесно связаны с системой управления фокусом. Библиотека предоставляет хуки, которые автоматизируют работу с фокусом и обеспечивают правильное взаимодействие с ассистивными технологиями.
useFocusRing Позволяет управлять визуальным состоянием фокуса и определять, был ли фокус установлен с клавиатуры:
import {useFocusRing} from '@react-aria/focus';
import {useRef} from 'react';
const inputRef = useRef(null);
const {isFocusVisible, focusProps} = useFocusRing();
<input ref={inputRef} {...focusProps} />
{isFocusVisible && <span>Фокус видим</span>}useFocus Обеспечивает управление событиями
фокуса (onFocus, onBlur) с учетом
ARIA-состояний:
import {useFocus} from '@react-aria/interactions';
const ref = useRef(null);
const {focusProps} = useFocus({onFocusChange: isFocused => console.log(isFocused)});
<div ref={ref} {...focusProps}>Фокусируемый элемент</div>При работе с React Aria часто возникает необходимость совместного
использования внутреннего рефа (для логики библиотеки) и внешнего рефа
(для родительского компонента). Функция mergeRefs
объединяет их без конфликтов:
import {mergeRefs} from '@react-aria/utils';
import {useRef, forwardRef} from 'react';
const Input = forwardRef((props, ref) => {
const internalRef = useRef(null);
return <input ref={mergeRefs(internalRef, ref)} {...props} />;
});
Это гарантирует, что библиотека и пользователь одновременно имеют доступ к DOM-элементу.
Когда компонент рендерится через портал
(ReactDOM.createPortal), управление рефами становится
критически важным, так как элемент фактически находится вне иерархии
родителя. React Aria автоматически корректно обрабатывает такие ситуации
при использовании своих хуков, но для пользовательских рефов нужно
убедиться, что реф передан на элемент внутри портала:
import {useRef} from 'react';
import {createPortal} from 'react-dom';
const modalRoot = document.getElementById('modal-root');
const ref = useRef(null);
{createPortal(
<div ref={ref}>Модальное окно</div>,
modalRoot
)}
mergeRefs, если компонент должен
работать с внешним рефом и внутренней логикой React Aria.useFocus и
useFocusRing для правильного ARIA-поведения.import {useTextField} from '@react-aria/textfield';
import {mergeRefs} from '@react-aria/utils';
import {useRef, forwardRef} from 'react';
const TextField = forwardRef((props, ref) => {
const internalRef = useRef(null);
const {inputProps} = useTextField(props, internalRef);
return <input {...inputProps} ref={mergeRefs(internalRef, ref)} />;
});
import {useButton} from '@react-aria/button';
import {useRef} from 'react';
const ref = useRef(null);
const {buttonProps} = useButton({onPress: () => alert('Clicked!')}, ref);
<button {...buttonProps} ref={ref}>Нажми меня</button>
import {useFocusRing} from '@react-aria/focus';
import {mergeRefs} from '@react-aria/utils';
import {useRef, forwardRef} from 'react';
const FocusInput = forwardRef((props, ref) => {
const internalRef = useRef(null);
const {focusProps, isFocusVisible} = useFocusRing();
return (
<div>
<input {...focusProps} ref={mergeRefs(internalRef, ref)} {...props} />
{isFocusVisible && <span>Фокус активен</span>}
</div>
);
});
Эти подходы демонстрируют, как рефы становятся связующим звеном между DOM, пользовательским кодом и React Aria, обеспечивая корректное управление фокусом, ARIA-состояниями и взаимодействие с ассистивными технологиями.