Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как создать 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 // или значение, которое ты передал
// }
Важные свойства:
- current - текущее значение ref
- Сохраняет значение между re-renders - не создается заново при каждом render
- Не вызывает 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
| Аспект | ref | state |
|---|---|---|
| Вызывает 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.