← Назад к вопросам
Можно ли технически положить DOM node в useState?
1.3 Junior🔥 81 комментариев
#Браузер и сетевые технологии
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Хранение DOM-узлов в useState: Технические детали
Технически возможно поместить DOM-узел в состояние через useState, однако это не рекомендуется и может привести к множеству проблем. Давайте разберёмся почему.
Что произойдёт если поместить DOM node в useState?
import { useState, useEffect } from 'react';
function ElementStorage() {
const [element, setElement] = useState(null);
useEffect(() => {
const div = document.getElementById('my-div');
setElement(div); // Технически сработает
}, []);
return (
<div>
<div id="my-div">Целевой элемент</div>
<button onClick={() => {
if (element) {
console.log(element.textContent); // Отобразит текст
}
}}>
Читать элемент
</button>
</div>
);
}
Да, такой код технически работает. React не выбросит ошибку и DOM-узел сохранится в state.
Почему это плохая идея?
1. Re-renders и потеря ссылки
// ПРОБЛЕМА: При каждом re-render ссылка может измениться
function BadExample() {
const [element, setElement] = useState(null);
// Этот обработчик вызывается при КАЖДОМ re-render
const handleClick = () => {
const newElement = document.querySelector('div');
setElement(newElement); // Новый re-render -> новая ссылка
// Может привести к infinite loop
};
return <button onClick={handleClick}>Клик</button>;
}
2. Проблемы сборки мусора (Memory Leak)
function MemoryLeakExample() {
const [element, setElement] = useState(null);
useEffect(() => {
const div = document.querySelector('div');
setElement(div); // Ссылка хранится в state
// Если элемент удалится из DOM, но останется в state,
// он не будет удалён сборщиком мусора
// Это особенно критично для больших элементов с слушателями событий
}, []);
// Если компонент размонтируется, ссылка остаётся в памяти
return null;
}
3. React не может отслеживать изменения DOM
function OutOfSync() {
const [element, setElement] = useState(null);
useEffect(() => {
setElement(document.getElementById('target'));
}, []);
// Если внешний код удалит элемент из DOM
// React не узнает об этом
const handleDelete = () => {
if (element) {
element.remove(); // DOM изменён
// Но state всё ещё хранит мёртвую ссылку!
}
};
return (
<div>
<div id="target">Элемент</div>
<button onClick={handleDelete}>Удалить из DOM</button>
</div>
);
}
Правильный подход: useRef
Для хранения ссылок на DOM-узлы используй useRef, а не useState:
import { useRef, useEffect } from 'react';
function CorrectWay() {
const elementRef = useRef(null);
useEffect(() => {
// ref.current всегда указывает на актуальный элемент
if (elementRef.current) {
console.log(elementRef.current.textContent);
}
}, []);
const handleFocus = () => {
elementRef.current?.focus();
};
return (
<div>
<input ref={elementRef} type="text" />
<button onClick={handleFocus}>Установить фокус</button>
</div>
);
}
Различия между useState и useRef для DOM
| Аспект | useState | useRef |
|---|---|---|
| Re-render при изменении | Да | Нет |
| Синхронизация с React | Да | Нет |
| Предназначение | Данные состояния | Ссылки на DOM/значения |
| Производительность | Хуже для DOM | Лучше для DOM |
| Отслеживание изменений | Автоматическое | Нужно вручную |
Когда всё же использовать state для DOM
Исключительно редко, для очень простых случаев:
function TextContent() {
const [text, setText] = useState('');
useEffect(() => {
const element = document.getElementById('display');
if (element) {
// Сохраняем не сам элемент, а его СОДЕРЖИМОЕ
setText(element.textContent);
}
}, []);
return <p>{text}</p>; // Используем данные, не сам элемент
}
Основное правило: хранишь данные -> useState, нужна ссылка на DOM -> useRef. Это фундаментальное различие в React-архитектуре, которое обеспечивает предсказуемость и производительность приложения.