오드컨셉 과제를 하던중
스크롤시 region데이터가 해당 window에서 보이는 위치로 이동되게 만드는 것을 구현하는데 매번 스크롤 이벤트가 불필요하게 발생되는 것을 막기 위해 디바운싱을 생각하게 되었다.
const FashionContainer = () => {
useEffect(() => {
function watchScroll() {
window.addEventListener("scroll", checkRegions);
}
watchScroll();
...
return () => {
window.removeEventListener("scroll", checkRegions);
};
}, []);
...
const checkRegions = () => {
let timer;
if (timer) {
console.log(timer, "if");
clearTimeout(timer);
}
timer = setTimeout(function () {
console.log(timer, "setTimeout");
setRegionHeight(window.pageYOffset);
}, 2000);
console.log(timer, "out");
};
...
return (
<MinWidth>
<Header />
{isLoading && <Modal />}
<FashionSection
productsData={products}
regionsData={regions}
clickBtn={clickBtn}
regionHeight={regionHeight}
/>
</MinWidth>
);
};
const MinWidth = styled.div`
min-width: 500px;
`;
export default FashionContainer;
주요부분을 제외하고 디바운스 부분만 집중해본다.
- 현재 timer가 이벤트 핸들러 함수내에서 선언되고 있다.
해당 결과를 보면 다음과 같다.
이런식으로 setTimeout이 한번의 스크롤만으로 11번이상 실행되는 것을 알 수있으며 추가로
if(timer)
부분이 전혀 실행되지 않는 것을 알 수 있다.
즉, timer를 계속 새로 정의하여let timer
if문에서 인식할 수 없는것이다.
const FashionContainer = () => {
let timer;
useEffect(() => {
function watchScroll() {
window.addEventListener("scroll", checkRegions);
}
watchScroll();
...
return () => {
window.removeEventListener("scroll", checkRegions);
};
}, []);
...
const checkRegions = () => {
if (timer) {
console.log(timer, "if");
clearTimeout(timer);
}
timer = setTimeout(function () {
console.log(timer, "setTimeout");
setRegionHeight(window.pageYOffset);
}, 2000);
console.log(timer, "out");
};
...
return (
<MinWidth>
<Header />
{isLoading && <Modal />}
<FashionSection
productsData={products}
regionsData={regions}
clickBtn={clickBtn}
regionHeight={regionHeight}
/>
</MinWidth>
);
};
const MinWidth = styled.div`
min-width: 500px;
`;
export default FashionContainer;
- 현재 timer가 이벤트 핸들러 함수 밖에서 선언되고 있다.
즉, 이전에 setTimeout의 받아온 timer의 값을 인식하고 있어
if(timer)
에서 값을 인식하여 처리할 수 있다.
해당 결과를 보면 다음과 같다.
out
과if
만 반복되며 가장 마지막에setTimeout
이 단한번만 실행된다.
즉, 디바운싱을 제대로 구현하는데는 성공했다.
다른 구글링에서는 React에서 timer를 상태값으로 useState를 사용하는데
사실 이부분은 아직 나도 어렵다.
적어도 이벤트 함수 내에서 timer를 선언하는 것은 제대로된 디바운싱 결과를 보여줄수 없다.
디바운싱을 쓰려면 이벤트 함수 밖에 timer를 정의하자!