В React реф (ref) — это объект, который позволяет напрямую взаимодействовать с DOM-элементами или экземплярами компонентов. В MUI рефы особенно важны, так как многие компоненты оборачиваются внутренними обертками, и прямой доступ к DOM через обычные селекторы невозможен. Использование рефов позволяет управлять фокусом, анимациями, скроллингом и другими низкоуровневыми операциями.
Для создания рефа используется хук useRef:
import { useRef } from 'react';
const inputRef = useRef(null);
Реф инициализируется значением null, после чего его
можно передать компоненту MUI через проп ref или
inputRef в зависимости от компонента.
MUI использует forwardRef, что позволяет передавать
рефы напрямую к базовому DOM-элементу, который лежит внутри компонента.
Пример с TextField:
import React, { useRef } from 'react';
import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
function MyForm() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<TextField label="Введите текст" inputRef={inputRef} />
<Button onCl ick={focusInput}>Фокус на поле</Button>
</div>
);
}
Ключевой момент: для компонентов, которые
оборачивают DOM-элемент (например, TextField), нужно
использовать inputRef, а не просто ref.
value + onChange) и рефы чаще применяются для
фокусировки или выделения текста..value).Пример установки значения через реф:
const setValue = () => {
inputRef.current.value = "Новое значение";
};
Для управления фокусом рефы являются стандартным решением:
inputRef.current.focus();
Для прокрутки к элементу:
inputRef.current.scrollIntoView({ beh * avior: 'smooth' });
MUI компоненты полностью поддерживают такой доступ при корректном
использовании ref или inputRef.
При создании собственного компонента на базе MUI важно использовать
forwardRef, чтобы родительский компонент мог передавать
реф:
import React, { forwardRef } from 'react';
import Button from '@mui/material/Button';
const MyButton = forwardRef((props, ref) => (
<Button ref={ref} {...props} />
));
Это гарантирует, что переданный реф будет указывать на реальный DOM-элемент кнопки.
Компоненты, которые рендерят свои элементы вне родительского DOM
(например, Popover, Menu, Modal),
требуют особого внимания. В таких случаях рефы передаются к
anchorEl или через колбэки:
import { useRef, useState } from 'react';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
function DropdownMenu() {
const buttonRef = useRef(null);
const [open, setOpen] = useState(false);
return (
<>
<Button ref={buttonRef} onCl ick={() => setOpen(true)}>Открыть меню</Button>
<Menu
anchorEl={buttonRef.current}
open={open}
onCl ose={() => setOpen(false)}
>
<MenuItem onCl ick={() => setOpen(false)}>Пункт 1</MenuItem>
<MenuItem onCl ick={() => setOpen(false)}>Пункт 2</MenuItem>
</Menu>
</>
);
}
useImperativeHandleЕсли требуется расширить функциональность рефа кастомного компонента,
используется useImperativeHandle:
import React, { useRef, forwardRef, useImperativeHandle } from 'react';
const CustomInput = forwardRef((props, ref) => {
const internalRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => internalRef.current.focus(),
clear: () => internalRef.current.value = '',
}));
return <input ref={internalRef} {...props} />;
});
const App = () => {
const customRef = useRef();
return (
<div>
<CustomInput ref={customRef} />
<button onCl ick={() => customRef.current.focus()}>Фокус</button>
<button onCl ick={() => customRef.current.clear()}>Очистить</button>
</div>
);
};
Преимущество: родительский компонент получает ограниченный интерфейс для управления дочерним элементом, не раскрывая весь DOM напрямую.
inputRef или ref.forwardRef и,
при необходимости, useImperativeHandle.anchorEl или аналогичные пропсы.ref.Использование рефов в MUI позволяет реализовать сложные пользовательские сценарии, управлять фокусом, анимациями и DOM напрямую, сохраняя при этом реактивность интерфейса и совместимость с компонентной архитектурой React.