useRef는 { current: initialValue } 객체를 반환합니다. 이 객체는 컴포넌트의 전체 생명주기 동안 유지되며,.current 속성을 변경해도 리렌더링이 발생하지 않습니다. React는 매 렌더링마다 동일한 ref 객체를 반환하므로, 렌더링 사이에 값을 유지하는 데 적합합니다.useRef는 렌더링 사이에 값을 유지하면서도 리렌더링을 트리거하지 않는 React 훅입니다.
useRef는 .current 속성을 가진 가변 객체를 반환합니다. DOM 요소에 직접 접근하거나, 타이머 ID, 이전 렌더링 값 등 리렌더링과 무관한 값을 저장할 때 사용합니다. useState와 달리 값을 변경해도 컴포넌트가 다시 렌더링되지 않습니다.
값 변경 시 리렌더링 여부와 DOM 참조, 이전 값 저장을 직접 확인하세요.
function Counter() {
const [stateCount, setStateCount] = useState(0);
const refCount = useRef(0);
const handleState = () => {
setStateCount(c => c + 1); // 리렌더링 O
};
const handleRef = () => {
refCount.current += 1; // 리렌더링 X
console.log(refCount.current);
};
console.log('렌더링 발생!');
return (/* ... */);
}실제 코드로 동작 원리를 확인하세요.
import { useRef, useEffect } from 'react';
function VideoPlayer() {
const videoRef = useRef(null);
const handlePlay = () => videoRef.current.play();
const handlePause = () => videoRef.current.pause();
return (
<div>
<video ref={videoRef} src="/video.mp4" />
<button onClick={handlePlay}>재생</button>
<button onClick={handlePause}>일시정지</button>
</div>
);
}
// 여러 요소에 ref 배열 사용
function ItemList({ items }) {
const itemsRef = useRef(new Map());
const scrollToItem = (id) => {
itemsRef.current.get(id)?.scrollIntoView({
behavior: 'smooth', block: 'nearest'
});
};
return items.map(item => (
<div key={item.id}
ref={(node) => {
if (node) itemsRef.current.set(item.id, node);
else itemsRef.current.delete(item.id);
}}
>
{item.name}
</div>
));
}useRef는 { current: initialValue } 객체를 반환합니다. 이 객체는 컴포넌트의 전체 생명주기 동안 유지되며,.current 속성을 변경해도 리렌더링이 발생하지 않습니다. React는 매 렌더링마다 동일한 ref 객체를 반환하므로, 렌더링 사이에 값을 유지하는 데 적합합니다.useState의 setter는 비동기적으로 상태를 업데이트하고 리렌더링을 예약하지만,useRef의 .current 변경은 즉시 반영되며 리렌더링하지 않습니다.