리액트 스크롤 이벤트(React Scroll Event) 적용하기
요즘은 다양한 웹 환경에서 스크롤 이벤트를 요청하는 경우가 이전에 비해 굉장히 많아졌습니다. 오히려 아무런 동적 애니메이션 효과나 이벤트가 없는 정적인 웹 화면이 무언가 심심하고 이상하게 생각되기도 합니다.
리엑트에서 스크롤 이벤트를 구현하는 방법은 사용자(유저)가 스크롤 이벤트를 발생시키는 지 확인하고 스크롤이 발생한다면 이벤트를 적용하는 방법이 가장 일반적으로 생각하는 방법입니다. 이를 위해서 scroll 이벤트를 이용하여 해당 값을 가져오게 됩니다. 하지만 실제로 이렇게 적용해보면 굉장히 많은 문제점이 발생됩니다.
- 스크롤 이벤트를 바로 적용한 경우
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll); //clean up
};
}, []);
const handleScroll = () => {
console.log('scrolled');
};
위와 같은 방식으로 구현을 한 후 콘솔창을 통해 확인을 하게 되면 사용자는 스크롤 이벤트가 많이 진행되지 않았음에도 불구하고 이벤트 지속적으로 발생해서 로그가 순식간에 무수히 많이 발생하는 것을 볼 수 있습니다. (🥶🥶🥶🥶 꺅~~~~~)
이런 이유가 발생하는 이유는 React의 특성상 변화가 있을 때 DOM을 다시 탐색하고 변화가 있는 부분을 Render하여 다시 그려주기(이 부분이 브라우저의 동작원리 중 리플로우, 리페인팅에 해당합니다.) 때문인데 위와 같은 방식으로 구현을 하게 되면 성능에도 문제가 발생합니다.
위와 같은 현상과 성능 개선을 위해 스크롤 이벤트에 Timer를 두어서 Timer안에서 이벤트가 발생하고 이벤트가 발생된 후 해당 타이머는 초기화를 시켜주어 이벤트의 중복을 통한 성능 지연을 방지합니다.
- 성능개선 코드
export default function App() {
const targetRef = useRef(null);
const handleScroll = () => {
console.log("scrolling");
if (window.scrollY > 0) {
targetRef.current.style.position = "fixed";
}
};
useEffect(() => {
const timer = setInterval(() => {
window.addEventListener("scroll", handleScroll);
}, 100);
return () => {
clearInterval(timer);
window.removeEventListener("scroll", handleScroll);
};
}, []);
return (
<div className="App">
<div ref={targetRef}>이벤트 발생위치</div>
</div>
);
}
위 코드로 적용하고 로그를 확인해보면 처음 코드와는 확연히 다르게 로그가 발생되는 것을 확인하실 수 있습니다.
감사합니다.
참고 : https://stackoverflow.com/questions/68751736/throttle-window-scroll-event-in-react-with-settimeout