Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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.