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

Как хранятся Ref элементы?

2.2 Middle🔥 201 комментариев
#React

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

Как хранятся Ref элементы в React

Ref (referencias) — это специальный механизм в React для прямого доступа к DOM элементам или инстансам компонентов. Это один из немногих способов «выйти из React» и работать с DOM напрямую.

Создание Ref

1. useRef хук (для функциональных компонентов)

import { useRef } from react;

function TextInput() {
  const inputRef = useRef(null);
  
  const handleClick = () => {
    inputRef.current.focus(); // Доступ к DOM элементу
  };
  
  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </>
  );
}

2. React.createRef (для классовых компонентов)

class TextInput extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }
  
  handleClick = () => {
    this.inputRef.current.focus();
  };
  
  render() {
    return (
      <>
        <input ref={this.inputRef} type="text" />
        <button onClick={this.handleClick}>Focus</button>
      </>
    );
  }
}

Что находится в ref.current

const ref = useRef(null);

// Для DOM элементов
<div ref={ref}>Hello</div>;
// ref.current содержит DOM node
console.log(ref.current); // <div>Hello</div>
console.log(ref.current.textContent); // "Hello"

// Для компонентов с forwardRef
const MyComponent = forwardRef((props, ref) => {
  return <input ref={ref} />;
});

const inputRef = useRef(null);
<MyComponent ref={inputRef} />;
// inputRef.current содержит инстанс компонента

Внутреннее хранение Ref

React хранит Ref как часть фибры (fiber) — внутренней структуры, которая отслеживает компонент и его DOM.

// Упрощённое представление внутренней структуры:
// React Fiber для компонента выглядит примерно так:
const fiber = {
  type: MyComponent,
  ref: { current: null }, // Вот где хранится Ref!
  hooks: [ /* хуки useRef, useState и т.д. */ ],
  dom: null,
};

// После рендера DOM элемента:
fiber.ref.current = actualDOMElement;

Инициализация и обновление

// useRef инициализируется один раз
const ref = useRef(initialValue);
// ref = { current: initialValue }

// Значение ref НЕ вызывает re-render при изменении
ref.current = newValue; // Компонент не перерендерится!

// Это отличает useRef от useState:
const [value, setValue] = useState(initialValue);
// setValue() запускает re-render

Различие между useRef и переменной

// ❌ Неправильно — переменная пересоздаётся при каждом рендере
function Component() {
  let ref = { current: null };
  // ref пересоздаётся при каждом рендере!
}

// ✅ Правильно — useRef создаётся один раз
function Component() {
  const ref = useRef(null);
  // ref существует между рендерами
}

Жизненный цикл Ref

function Component() {
  const ref = useRef(null);
  
  useEffect(() => {
    // Здесь ref уже содержит DOM элемент
    console.log(ref.current); // <input />
    
    return () => {
      // Cleanup — ref может быть null
    };
  }, []);
  
  // Во время рендера ref может быть null
  console.log(ref.current); // null (пока рендер не завершён)
  
  return <input ref={ref} />;
}

Практические примеры

Управление фокусом:

function SearchInput() {
  const inputRef = useRef(null);
  
  const handleSearch = () => {
    inputRef.current.focus();
  };
  
  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={handleSearch}>Search</button>
    </>
  );
}

Доступ к методам DOM:

function VideoPlayer() {
  const videoRef = useRef(null);
  
  const play = () => videoRef.current.play();
  const pause = () => videoRef.current.pause();
  
  return (
    <>
      <video ref={videoRef}>
        <source src="movie.mp4" />
      </video>
      <button onClick={play}>Play</button>
      <button onClick={pause}>Pause</button>
    </>
  );
}

Работа с библиотеками (jQuery, D3):

function D3Chart() {
  const svgRef = useRef(null);
  
  useEffect(() => {
    if (svgRef.current) {
      // Использование D3 с реальным DOM элементом
      d3.select(svgRef.current)
        .append("circle")
        .attr("r", 40);
    }
  }, []);
  
  return <svg ref={svgRef} />;
}

Важные моменты

  • Не переусложняй: Ref нужен только для особых случаев (фокус, медиа, интеграция с третьими библиотеками)
  • Избегай доступа к Ref во время рендера: это нарушает React парадигму
  • forwardRef для пробрасывания Ref в компоненты: нестандартный проп, требует явной пробраски
  • Ref НЕ вызывает re-render, в отличие от state

Краткий вывод: Ref — это безопасный способ прямого доступа к DOM, но используй его осторожно. В 90% случаев есть React способ сделать то же самое.