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

Как создать ref в React?

2.0 Middle🔥 281 комментариев
#React#Архитектура и паттерны

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Как создать ref в React

Ref (reference) в React - это способ получить прямой доступ к DOM элементам или экземплярам компонентов. Это один из главных инструментов, когда нужна прямая манипуляция DOM, но его нужно использовать осторожно.

useRef хук

Это основной способ создания ref в современном React (с функциональными компонентами).

import { useRef } from 'react';

const MyComponent = () => {
  const inputRef = useRef(null);
  
  const handleFocus = () => {
    inputRef.current.focus();
  };
  
  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleFocus}>Focus Input</button>
    </>
  );
};

Что такое useRef

Возвращаемое значение:

const ref = useRef(null);

// ref это объект с одним свойством:
// {
//   current: null  // или значение, которое ты передал
// }

Важные свойства:

  1. current - текущее значение ref
  2. Сохраняет значение между re-renders - не создается заново при каждом render
  3. Не вызывает re-render - в отличие от setState

Способ 1: Доступ к DOM элементу

Самый частый случай - получить доступ к input, видео плеерлюку и т.д.

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

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

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

Способ 3: Хранение значений между re-renders

Ref можно использовать как хранилище значения, которое не вызывает re-render.

function Timer() {
  const countRef = useRef(0);
  
  const handleClick = () => {
    countRef.current++;
    console.log(`Clicked ${countRef.current} times`);
  };
  
  return (
    <>
      <button onClick={handleClick}>Click me</button>
      <p>Count (in console): {countRef.current}</p>
      {/* Отобразится всегда 0, потому что нет re-render */}
    </>
  );
}

// Если нужен re-render, используй useState
function TimerWithState() {
  const [count, setCount] = useState(0);
  
  const handleClick = () => {
    setCount(count + 1);
  };
  
  return (
    <>
      <button onClick={handleClick}>Click me</button>
      <p>Count: {count}</p> {/* Обновляется при каждом клике */}
    </>
  );
}

Способ 4: Сохранение timer ID

Частый случай - нужно сохранить ID таймера для последующего отмены.

function Stopwatch() {
  const timerRef = useRef(null);
  const [time, setTime] = useState(0);
  
  const handleStart = () => {
    timerRef.current = setInterval(() => {
      setTime(t => t + 1);
    }, 1000);
  };
  
  const handleStop = () => {
    clearInterval(timerRef.current);
  };
  
  return (
    <>
      <p>Time: {time}s</p>
      <button onClick={handleStart}>Start</button>
      <button onClick={handleStop}>Stop</button>
    </>
  );
}

Способ 5: forwardRef для компонентов

По умолчанию ref не передаются в компоненты. Используй forwardRef для передачи ref.

import { forwardRef } from 'react';

// Обычный компонент (ref не работает)
const Input = ({ label }, ref) => (
  <input ref={ref} />
);

// С forwardRef (ref работает)
const Input = forwardRef(({ label }, ref) => (
  <>
    <label>{label}</label>
    <input ref={ref} />
  </>
));

// Использование
function App() {
  const inputRef = useRef(null);
  
  const handleFocus = () => {
    inputRef.current.focus();
  };
  
  return (
    <>
      <Input label="Enter text" ref={inputRef} />
      <button onClick={handleFocus}>Focus</button>
    </>
  );
}

Способ 6: useImperativeHandle для контроля проксиранных методов

Если хочешь контролировать, какие методы доступны через ref.

import { forwardRef, useImperativeHandle } from 'react';

const Input = forwardRef(({ label }, ref) => {
  const inputRef = useRef(null);
  
  // Определяем, какие методы доступны через ref
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => inputRef.current.value = '',
    getValue: () => inputRef.current.value
  }));
  
  return <input ref={inputRef} />;
});

// Использование
function App() {
  const inputRef = useRef(null);
  
  const handleClear = () => {
    inputRef.current.clear();
  };
  
  const handleGetValue = () => {
    console.log(inputRef.current.getValue());
  };
  
  return (
    <>
      <Input label="Name" ref={inputRef} />
      <button onClick={handleClear}>Clear</button>
      <button onClick={handleGetValue}>Get Value</button>
    </>
  );
}

Когда использовать ref (правильные случаи)

// 1. Управление фокусом
inputRef.current.focus();

// 2. Запуск анимаций
const element = elementRef.current;
element.style.animation = 'slideIn 0.3s';

// 3. Работа с медиа плеерами
videoRef.current.play();

// 4. Интеграция с non-React кодом
jQueryRef.current = $(element).datepicker();

// 5. Выбор текста
textareaRef.current.select();

Когда НЕ использовать ref (частые ошибки)

// ПЛОХО - используй state вместо ref
const counterRef = useRef(0);
handler = () => counterRef.current++; // Не вызывает re-render

// ХОРОШО - используй useState
const [counter, setCounter] = useState(0);
handler = () => setCounter(counter + 1);

// ПЛОХО - получение значения input через ref
const inputRef = useRef(null);
const value = inputRef.current.value;

// ХОРОШО - используй onChange и state
const [value, setValue] = useState('');
<input value={value} onChange={e => setValue(e.target.value)} />

Сравнение ref vs state

Аспектrefstate
Вызывает re-renderНетДа
MutableДаНет (직접 изменять запрещено)
Информация в UIНетДа
ИзменениеСинхронноеАсинхронное
Получение новых значенийВсегда текущееМожет быть "застарелое"

createRef для class компонентов

В старых class компонентах используется createRef (теперь редко используется).

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

Вывод

Для создания ref используй useRef в функциональных компонентах. Это вернет объект с свойством current, которое указывает на DOM элемент или экземпляр компонента. Используй ref только когда действительно нужна прямая манипуляция DOM, в большинстве случаев лучше использовать state и props.

Как создать ref в React? | PrepBro