← Назад к вопросам

Ссылаясь на элемент DOM через useRef, сохраняется ссылка на элемент в DOM или Virtual DOM

2.0 Middle🔥 211 комментариев
#JavaScript Core#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Отличный вопрос, который затрагивает ключевые различия между реальным и виртуальным DOM в React.

Краткий и прямой ответ

useRef сохраняет ссылку напрямую на реальный (нативный) элемент в браузерном DOM. Он не ссылается на элемент в Virtual DOM.


Подробное объяснение

Чтобы понять, почему это так, необходимо четко разделить три сущности в ментальной модели React:

1. Виртуальный DOM (Virtual DOM)

Это легковесное JavaScript-представление реального DOM. По сути, это дерево объектов (React-элементов и Fiber -узлов), которое живет в памяти JavaScript-движка. React использует его для сравнения (diffing) и определения минимального набора изменений, которые нужно применить к реальному DOM.

2. Реальный DOM (Browser DOM)

Это нативное дерево объектов, управляемое браузером, которое непосредственно отрисовывается на экране. Работа с ним через JavaScript API (например, document.getElementById()) — дорогостоящая операция.

3. Ссылка ref, создаваемая useRef

useRef создает изменяемый JavaScript-объект, свойство .current которого можно присвоить чему угодно. Когда этот ref передается в атрибут ref JSX-элемента, React берет на себя обязательство самостоятельно заполнить ref.current ссылкой на соответствующий нативный DOM-узел после того, как элемент будет примонтирован (или обновлен).

Механизм работы

Вот что происходит пошагово:

  1. Вы создаете ссылку: const myRef = useRef(null).
  2. Вы передаете ее элементу: <div ref={myRef}>...</div>.
  3. React обрабатывает ваш JSX и строит или обновляет Virtual DOM.
  4. После этапа "commit" (фиксации изменений), когда вычисления в Virtual DOM завершены и React готов применить изменения к реальному DOM, он находит соответствующий реальный DOM-элемент.
  5. **React присваивает myRef.current этот самый реальный DOM-
import { useRef, useEffect } from 'react';

function MyComponent() {
  // Создается пустой мутабельный объект
  const divRef = useRef(null);

  useEffect(() => {
    // После монтирования компонента (commit phase)
    // divRef.current УКАЗЫВАЕТ НА РЕАЛЬНЫЙ HTMLDivElement в браузере
    console.log(divRef.current); // Выведет: <div>...</div>
    console.log(divRef.current instanceof HTMLDivElement); // Выведет: true

    // Мы можем использовать нативные DOM API
    divRef.current.style.backgroundColor = 'lightblue';
    divRef.current.addEventListener('click', handler);
  }, []);

  // Этот div — описание в JSX/Virtual DOM.
  // Атрибут ref — инструкция для React.
  return <div ref={divRef}>Этот элемент доступен по ссылке</div>;
}

Почему это важно и какие последствия

Прямой доступ к нативному DOM

Поскольку вы получаете прямой доступ, вы можете:

  • Использовать нативные методы (focus(), blur(), getBoundingClientRect()).
  • Интегрироваться со сторонними библиотеками (карты, графики, плееры), которые требуют передачи DOM-элемента.
  • Выполнять императивные манипуляции (style, classList), обходя React.

Несовпадение с жизненным циклом Virtual DOM

Ссылка ref.current существует и доступна даже между рендерами React, что является ключевым отличием от состояния (useState). Обновление ref.current не вызывает повторный рендер.

Однако важно помнить:

  • При демонтировании компонента React устанавливает ref.current обратно в null.
  • Значение в ref.current может "отставать" на один рендер, если вы читаете его сразу после обновления состояния, так как эффекты (useEffect) срабатывают после фазы commit.
function ProblematicExample() {
  const inputRef = useRef(null);
  const [value, setValue] = useState('');

  const handleClick = () => {
    setValue('Новое значение');
    // НЕРАБОТАЕТ! DOM еще не обновлен.
    // inputRef.current.value все еще содержит старое значение.
    console.log(inputRef.current.value); // Старое значение
  };

  useEffect(() => {
    // РАБОТАЕТ! DOM уже обновлен React'ом.
    console.log(inputRef.current.value); // 'Новое значение'
  }, [value]);

  return (
    <>
      <input ref={inputRef} value={value} onChange={(e) => setValue(e.target.value)} />
      <button onClick={handleClick}>Обновить</button>
    </>
  );
}

Аналогия для понимания

Представьте, что вы архитектор (React/Virtual DOM), который делает чертежи здания. У вас есть доверенный курьер (useRef). Вы даете курьеру инструкцию: "Когда строители (браузер) по этим чертежам построят реальную дверь №5 (DOM-элемент), положи в этот сейф (ref.current) ее точный физический адрес". Курьер не взаимодействует с чертежами, он взаимодействует только с конечным, построенным объектом.

Вывод

Таким образом, useRef — это мост из императивного мира нативного DOM в декларативный мир React. Он позволяет React'у дать вам в руки конкретный, уже созданный им нативный DOM- , сохраняя при этом контроль над процессом обновлений и производительностью через Virtual DOM. Это мощный инструмент, который следует использовать осознанно, чтобы не нарушить декларативную модель и согласованность данных в React-приложении.

Ссылаясь на элемент DOM через useRef, сохраняется ссылка на элемент в DOM или Virtual DOM | PrepBro