일정 시간이 지나고 나서야 어떤 행동을 수행하도록 할 때 setTimeout을 쓰게 됩니다.
다만 모종의 이유로 그 행동이 취소됐을 때에는 그 id를 가지고 설정된 timeout을 해제해야 하는데,
그 id를 저장하는데 에 useRef가 쓰입니다.
const DelayedHoverMenu: React.FC = () => {
const [showMenu, setShowMenu] = useState(false);
const hoverTimer = useRef<number | null>(null);
const handleMouseEnter = () => {
hoverTimer.current = window.setTimeout(() => {
setShowMenu(true);
}, 300);
};
const handleMouseLeave = () => {
if (hoverTimer.current) {
clearTimeout(hoverTimer.current);
hoverTimer.current = null;
}
setShowMenu(false);
};
useEffect(() => {
return () => {
if (hoverTimer.current) {
clearTimeout(hoverTimer.current);
}
};
}, []);
return (
<div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
Hover me!
{showMenu && <div>Menu content...</div>}
</div>
);
};
export default DelayedHoverMenu;
위의 컴포넌트는 마우스가 요소 위에 0.3초 동안 머물렀을 때 메뉴를 나타내고, 마우스가 요소를 벗어났을 때 메뉴를 숨깁니다.
useRef는 타이머 ID를 저장하는데 사용되며, useEffect는 컴포넌트가 언마운트될 때 타이머를 정리하기 위해 사용됩니다.
`useRef`를 사용하는 이유는 컴포넌트에서 변경 가능한 참조 값을 가지기 위해서입니다. 이 경우에는 타이머의 ID를 저장하고 관리하기 위해 사용됩니다.
`setTimeout` 함수는 호출 후 일정 시간이 지난 다음 주어진 함수를 실행하는데, 이 때 반환되는 값은 타이머의 ID입니다. 이 ID를 사용하여 `clearTimeout` 함수를 호출하면 타이머를 취소할 수 있습니다.
이 문제의 경우에, 사용자가 요소 위에 마우스를 올리고 0.3초 내에 마우스를 올려놓은 상태에서 벗어나면 메뉴를 보여주지 않아야 합니다. 따라서 `setTimeout`으로 설정한 타이머를 취소해야 합니다. 이를 위해 `setTimeout`의 반환값인 타이머 ID를 `useRef`에 저장하고, 필요한 경우 이를 참조하여 `clearTimeout`을 호출합니다.
const handleMouseEnter = () => {
hoverTimer.current = window.setTimeout(() => {
setShowMenu(true);
}, 300);
};
const handleMouseLeave = () => {
if (hoverTimer.current) {
clearTimeout(hoverTimer.current);
hoverTimer.current = null;
}
setShowMenu(false);
};
`handleMouseLeave`에서는 사용자가 요소를 벗어났을 때 `hoverTimer.current`에 저장된 타이머 ID를 참조하여 `clearTimeout`을 호출하고, 메뉴를 숨깁니다.
이런 식으로 `useRef`는 React 컴포넌트 내에서 변경 가능한 값을 저장하고 참조하기 위해 사용됩니다.
왜 useRef에 저장해?
`useRef`를 사용하는 주된 이유는 React에서 컴포넌트의 리렌더링에 영향을 주지 않으면서도 값을 참조하거나 변경할 수 있기 때문입니다.
만약 `useState`를 사용해서 타이머 ID를 저장하게 된다면, 타이머 ID의 값이 변경될 때마다 컴포넌트가 리렌더링 될 것입니다. 그러나 실제로 우리는 그 값의 변경으로 인한 컴포넌트의 리렌더링을 원하지 않습니다. 이런 경우에 `useRef`가 유용하게 쓰입니다.
`useRef`의 특징:
1. `useRef`는 `.current` 프로퍼티를 통해 접근될 수 있는 변경 가능한 ref 객체를 반환합니다.
2. `useRef`의 값이 바뀌어도 컴포넌트는 리렌더링되지 않습니다.
3. `useRef`는 컴포넌트의 여러 렌더링 사이에서도 값을 유지합니다.
이런 특성 때문에, 값의 변경에 따라 리렌더링을 피하면서도 그 값을 컴포넌트 내에서 지속적으로 유지하고자 할 때 `useRef`를 사용합니다. 타이머 ID, DOM 요소, 외부 라이브러리의 인스턴스 등, 리액트의 렌더링 사이클에 영향을 주지 않는 값을 관리할 때 주로 사용됩니다.
그러면 전역변수로 선언하는거랑 무슨 차이가 있어?
생명주기
캡슐화
리렌더링