Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как обратиться к DOM из React
Обращение к DOM из React должно быть редким исключением. React управляет DOM виртуально, и прямое обращение обычно считается антипаттерном. Однако есть легитимные случаи, когда это необходимо.
Способ 1: useRef() хук (Functional Components)
useRef() — это встроенный хук React для сохранения ссылки на DOM элемент.
Базовый пример:
import { useRef } from 'react';
function TextInput() {
const inputRef = useRef(null);
const handleClick = () => {
// Обращаемся к DOM элементу через .current
inputRef.current.focus();
console.log('Значение инпута:', inputRef.current.value);
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={handleClick}>Fokus</button>
</>
);
}
Пример с видео элементом:
function VideoPlayer() {
const videoRef = useRef(null);
const handlePlay = () => {
videoRef.current.play();
};
const handlePause = () => {
videoRef.current.pause();
};
return (
<>
<video ref={videoRef} width="640" height="360">
<source src="video.mp4" type="video/mp4" />
</video>
<button onClick={handlePlay}>Play</button>
<button onClick={handlePause}>Pause</button>
</>
);
}
Способ 2: Обращение к DOM элементам в useEffect()
useEffect() позволяет выполнять побочные эффекты после рендера:
import { useRef, useEffect } from 'react';
function Counter() {
const countRef = useRef(null);
const [count, setCount] = React.useState(0);
useEffect(() => {
// Обновляем текст в DOM
if (countRef.current) {
countRef.current.textContent = count;
}
}, [count]);
return (
<>
<div ref={countRef}>0</div>
<button onClick={() => setCount(count + 1)}>Increment</button>
</>
);
}
Способ 3: Вычисление размеров и позиций
Измерение элемента:
import { useRef, useEffect, useState } from 'react';
function MeasureElement() {
const elementRef = useRef(null);
const [width, setWidth] = useState(0);
useEffect(() => {
if (elementRef.current) {
setWidth(elementRef.current.offsetWidth);
}
}, []);
return (
<>
<div ref={elementRef}>Элемент</div>
<p>Ширина: {width}px</p>
</>
);
}
Использование ResizeObserver:
function ResponsiveElement() {
const containerRef = useRef(null);
const [width, setWidth] = useState(0);
useEffect(() => {
const resizeObserver = new ResizeObserver((entries) => {
setWidth(entries[0].contentRect.width);
});
if (containerRef.current) {
resizeObserver.observe(containerRef.current);
}
return () => resizeObserver.disconnect();
}, []);
return <div ref={containerRef}>Ширина: {width}px</div>;
}
Способ 4: Управление фокусом
Автоматический фокус на инпут:
function Form() {
const firstInputRef = useRef(null);
useEffect(() => {
// Фокусируемся на первый инпут при загрузке
firstInputRef.current?.focus();
}, []);
return (
<form>
<input ref={firstInputRef} type="text" placeholder="Имя" />
<input type="email" placeholder="Email" />
</form>
);
}
Управление фокусом между элементами:
function FormWithNavigation() {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const handleEmailKeyPress = (e) => {
if (e.key === 'Enter') {
passwordRef.current?.focus();
}
};
return (
<form>
<input
ref={emailRef}
type="email"
onKeyPress={handleEmailKeyPress}
/>
<input ref={passwordRef} type="password" />
</form>
);
}
Способ 5: Работа с методами элементов
Управление плеером:
function AudioPlayer() {
const audioRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
const togglePlay = () => {
if (isPlaying) {
audioRef.current?.pause();
} else {
audioRef.current?.play();
}
setIsPlaying(!isPlaying);
};
return (
<>
<audio ref={audioRef} src="song.mp3" />
<button onClick={togglePlay}>
{isPlaying ? 'Pause' : 'Play'}
</button>
</>
);
}
Способ 6: Получение текущего значения инпута
function SearchForm() {
const searchRef = useRef(null);
const handleSearch = () => {
const query = searchRef.current.value;
console.log('Поиск:', query);
// Выполняем поиск
};
return (
<>
<input ref={searchRef} type="text" placeholder="Поиск..." />
<button onClick={handleSearch}>Поиск</button>
</>
);
}
Способ 7: Обращение к кастомным компонентам
Использование forwardRef():
import { useRef, forwardRef } from 'react';
const CustomInput = forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
function App() {
const customInputRef = useRef(null);
const handleFocus = () => {
customInputRef.current?.focus();
};
return (
<>
<CustomInput ref={customInputRef} />
<button onClick={handleFocus}>Focus</button>
</>
);
}
Использование useImperativeHandle():
import { useRef, useImperativeHandle, forwardRef } from 'react';
const TextInput = forwardRef((props, ref) => {
const inputRef = useRef(null);
useImperativeHandle(ref, () => ({
focus: () => inputRef.current?.focus(),
clear: () => {
inputRef.current.value = '';
}
}));
return <input ref={inputRef} {...props} />;
});
function App() {
const textInputRef = useRef(null);
return (
<>
<TextInput ref={textInputRef} />
<button onClick={() => textInputRef.current?.focus()}>Focus</button>
<button onClick={() => textInputRef.current?.clear()}>Clear</button>
</>
);
}
Способ 8: Обращение через document.getElementById()
Когда нельзя использовать ref:
function App() {
useEffect(() => {
// Получаем элемент из документа
const footer = document.getElementById('footer');
if (footer) {
footer.style.display = 'none';
}
}, []);
return <div id="footer">Footer</div>;
}
Способ 9: querySelector и querySelectorAll
function ListManager() {
const containerRef = useRef(null);
useEffect(() => {
// Находим все элементы внутри контейнера
const items = containerRef.current?.querySelectorAll('li');
if (items) {
console.log('Найдено элементов:', items.length);
}
}, []);
return (
<ul ref={containerRef}>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
);
}
Когда НЕ использовать ref
// ❌ Плохо: используем ref для того, что можно сделать через состояние
const badExample = () => {
const countRef = useRef(0);
return <button onClick={() => countRef.current++}>{countRef.current}</button>;
// Не обновит UI!
};
// ✅ Хорошо: используем состояние
const goodExample = () => {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
};
Выводы
- useRef() — основной способ обращения к DOM в functional components
- useEffect() — для выполнения побочных эффектов после рендера
- forwardRef() и useImperativeHandle() — для передачи ref в кастомные компоненты
- Избегай обращения к DOM, когда можно использовать состояние и props
- Ref идеален для управления фокусом, медиа плеерами и значениями инпутов
- Всегда очищай слушатели и подписки в return функции useEffect