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

Что такое refs?

1.3 Junior🔥 181 комментариев
#React

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

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

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

Refs в React

Refs (References) — это механизм в React для прямого доступа к DOM-элементам или экземплярам компонентов. Это один из способов выхода из парадигмы "reactive data flow" React, когда тебе нужен прямой доступ к чему-то внутри.

Когда нужны refs?

Refs используются редко, только в специфических случаях:

// 1. Управление фокусом на элементе
const inputRef = useRef(null);
const focus = () => inputRef.current.focus();

// 2. Запуск анимаций
const divRef = useRef(null);
const startAnimation = () => divRef.current.animate(...);

// 3. Интеграция с jQuery или другими библиотеками
const jqueryElement = jQuery(divRef.current);

// 4. Получение значения из input (редко — лучше использовать state)
const inputRef = useRef(null);
const handleSubmit = () => console.log(inputRef.current.value);

// 5. Доступ к методам компонента
const videoRef = useRef(null);
const play = () => videoRef.current.play();

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

В функциональных компонентах (современный способ):

import { useRef } from 'react';

function TextInput() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus();
  };

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>Focus</button>
    </>
  );
}

В классовых компонентах (старый способ):

class TextInput 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>
      </>
    );
  }
}

useRef vs useState

useState — для данных, которые влияют на рендер. useRef — для данных, которые НЕ должны вызывать рендер.

// useState — вызывает рендер
function Counter1() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

// useRef — НЕ вызывает рендер
function Counter2() {
  const countRef = useRef(0);
  const handleClick = () => {
    countRef.current++;
    console.log(countRef.current); // 1, 2, 3...
  };
  return <button onClick={handleClick}>Click me</button>;
}

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

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

function SearchInput() {
  const searchRef = useRef(null);

  useEffect(() => {
    // Автоматически фокусируем поле при загрузке
    searchRef.current?.focus();
  }, []);

  return <input ref={searchRef} placeholder="Search..." />;
}

Доступ к медиа-элементам:

function VideoPlayer() {
  const videoRef = useRef(null);

  return (
    <>
      <video ref={videoRef} src="movie.mp4" />
      <button onClick={() => videoRef.current?.play()}>Play</button>
      <button onClick={() => videoRef.current?.pause()}>Pause</button>
    </>
  );
}

Хранение предыдущего значения:

function Counter() {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef(null);

  useEffect(() => {
    prevCountRef.current = count;
  }, [count]);

  return (
    <>
      <p>Now: {count}, Before: {prevCountRef.current}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </>
  );
}

Отмера времени без вызова рендера:

function Stopwatch() {
  const intervalRef = useRef(null);
  const [time, setTime] = useState(0);

  const start = () => {
    intervalRef.current = setInterval(() => {
      setTime(t => t + 1);
    }, 1000);
  };

  const stop = () => {
    clearInterval(intervalRef.current);
  };

  return (
    <>
      <p>{time}s</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </>
  );
}

forwardRef — передача ref в компонент

Обычные функциональные компоненты не получают ref как параметр. Для этого используется forwardRef:

// Компонент не получит ref
function Input(props) {
  return <input {...props} />; // ref не будет работать!
}

// Нужно использовать forwardRef
const Input = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});

// Теперь можно использовать
function App() {
  const inputRef = useRef(null);
  return <Input ref={inputRef} />;
}

Когда НЕ использовать refs

// ❌ Плохо — можно сделать через state
const inputRef = useRef('');
const handleChange = (e) => {
  inputRef.current = e.target.value;
};

// ✅ Хорошо — используй state
const [value, setValue] = useState('');
const handleChange = (e) => setValue(e.target.value);

// ❌ Плохо — можно вызвать метод напрямую
const childRef = useRef(null);
const handleClick = () => childRef.current.doSomething();

// ✅ Хорошо — передай через props
const [shouldDo, setShouldDo] = useState(false);
<Child shouldDo={shouldDo} />

Важные правила

1. Не переусложняй — сначала try state

Refs — это escape hatch (запасной выход). Если можно решить через state, делай через state.

2. useRef не вызывает рендер

const countRef = useRef(0);
countRef.current++; // компонент НЕ перерисуется

3. ref.current может быть null

const ref = useRef(null);

useEffect(() => {
  // Может быть null!
  ref.current?.focus();
}, []);

4. Refs — это "выход из реакта"

Они нарушают парадигму reactive data flow. Используй редко и только когда другого пути нет.

На собеседовании

Краткий ответ: Refs — это способ прямого доступа к DOM-элементам или экземплярам компонентов в React. Создаются через useRef, используются редко, только когда нужен прямой доступ.

Развёрнутый ответ: Refs позволяют напрямую взаимодействовать с DOM, что нужно для фокуса, анимаций или интеграции с внешними библиотеками. Главное отличие от state — ref не вызывает рендер. forwardRef используется для передачи ref в функциональные компоненты. Wichtig помнить, что refs — это escape hatch, и сначала нужно try state.

Что такое refs? | PrepBro