react에서 권장하는 useEffect의 사용법은
component 내부에서 선언함으로써 state를 사용 가능하게끔 component scope 내부에 넣어주는 것이다.
...
function logic() {
setScrollY(window.pageYOffset);
console.log(scrollY);
}
useEffect(() => {
function watchScroll() {
window.addEventListener("scroll", logic);
}
watchScroll();
return () => {
window.removeEventListener("scroll", logic);
};
});
...
addEventListener는 window에서 특정 이벤트의 발생을 감지해 callback 함수를 실행시킨다.
useEffect는 렌더링이 끝나고 나서 실행된다.
setState는 렌더링을 유발시킨다.
위의 세 가지 개념을 적절히 조합해보자.
useEffect내부에 addEventListener로 화면이 그려지고 나서 실행되는 이벤트를 감시하는 감시자가 있다.
이는 특정 이벤트가 발생하였을 때 callback함수를 작동시키므로 callback함수에 setState를 넣어준다
eventListener에 의해 state가 작동하고 이로인해 렌더링이 새로 진행된다. return을 통해 eventListener을 종료시킨다. 렌더가 다시 시작되었으므로 useEffect는 다시 시작되어 eventListener의 조건이 발동될 때 마다 위의 1~3의 과정을 계속 반복한다.
! 리액트에서 setState로 인한 렌더링은 react에서 정한 최적화 방식에 따라 렌더링 된다. setState의 실행을 확실히 보증받기 위해서는 callback형태로 넘겨주어야 한다.
(react 공식 document)
이를 조금 줄여보면
...component...
useEffect(() => {
(() => {
window.addEventListener("scroll", () => setScrollY(window.pageYOffset));
console.log(scrollY);
})();
return () => {
window.removeEventListener("scroll", () =>
setScrollY(window.pageYOffset)
);
};
})
...
return(...)
eventListener는 이벤트 트리거가 작동되기만을 계속 기다리고 있다. 이는 component가 종료되어도 계속 실행되고 있을 가능성이 높다. (확인을 하지는 못했습니다.)
그럴 가능성이 있다고 하면 return으로 종료시켜주면 그만이다.