문제상황
Tooltip에 mouse hover할때마다 스크롤이 빠르게 생겼다 사라졌다.
overflow hidden인데도 아래와 같은 현상이 발생되었다.

원인
확실하진 않지만, hover 할때마다 x, y의 위치를 계산해 modal을 띄워주고 있는데, hover 속도에 비해 위치 계산하는 로직이 늦게 실행되기 때문인 것 같다.
const openTooltip = () => {
setIsHover(true);
};
const closeTooltip = () => {
setIsHover(false);
};
useEffect(() => {
if (!anchorRef.current || !contentRef.current) {
return;
}
const anchorRect = anchorRef.current.getBoundingClientRect();
const contentRect = contentRef.current.getBoundingClientRect();
const { x, y } = calcAnchorCoord({
anchorRect,
contentRect,
anchorOrigin,
transformOrigin,
anchorPosition,
});
contentRef.current.style.left = `${x}px`;
contentRef.current.style.top = `${y}px`;
}, [isHover]);해결법
- setTimeOut
tooltip을 open시에 스크롤이 생겼다 사라지므로 setIsHover(true)를 setTimeout으로 감싸주었더니 해결되었다.
const openTooltip = () => {
setTimeout(() => {
setIsHover(true);
});
};그렇지만, setTimeout으로 해결하는 것은 왠지 꼼수(?)같은 느낌이 들어, 다른 방법을 찾아 헤맸다.
- useLayoutEffect
위치 계산 하는 로직에 useEffect 대신 useLayoutEffect를 사용하니 문제가 해결되었다.
useLayoutEffect(() => {
if (!anchorRef.current || !contentRef.current) {
return;
}
const anchorRect = anchorRef.current.getBoundingClientRect();
const contentRect = contentRef.current.getBoundingClientRect();
const { x, y } = calcAnchorCoord({
anchorRect,
contentRect,
anchorOrigin,
transformOrigin,
anchorPosition,
});
contentRef.current.style.left = `${x}px`;
contentRef.current.style.top = `${y}px`;
}, [isHover]);useEffect vs useLayoutEffect
useEffect
- 컴포넌트들이 render(DOM Tree를 구성하기 위해 각 element의 스타일 속성을 계산하는 과정)와 paint(실제 스크린에 Layout을 표시하고 업데이트하는 과정)된 후 실행된다.
비동기적으로 실행된다.
paint된 후 실행되기 때문에, useEffect 내부에 dom에 영향을 주는 코드가 있을 경우 사용자 입장에서는 화면의 깜빡임을 보게될 수 있다.
useLayoutEffect
https://ko.reactjs.org/docs/hooks-reference.html#uselayouteffect
- 컴포넌트들이 render된 후 실행되며, 그 이후에 paint가 된다.
동기적으로 실행된다.
paint가 되기전에 실행되기 때문에 dom을 조작하는 코드가 존재하더라도 사용자는 깜빡임을 경험하지 않는다.
이러한 useEffect와 useLayoutEffect의 차이점 때문에
useEffect를 사용했을 땐, tooltip을 마우스오버했을때 깜빡거리며 스크롤이 생겼다 사라지는 현상이 나타났고 useLayoutEffect을 사용하니 문제가 해결되었던 것 같다.
setTimeOut으로 해결되었던 이유는?

내 예상으로는 호출스택에 쌓여있던 모든 것들이 처리되고 난 후에 밑의 코드가 실행되었기 때문..? 🤔