우선 Side Effect라는 단어에 대해 알아야한다.
💬 컴퓨터 과학에서 함수가 결과값 이외에 다른 상태를 변경시킬 때 부작용이 있다고 말한다. - 위키피디아
함수가 어떤 동작을 할 때, input - output 이외의 다른 값을 조작한다면, 이 함수에는 Side Effect(부수 효과) 가 있다고 표현한다.
하지만 그 Side Effect들은 state, props의 변화가 있을 때마다 렌더링되어 그 로직이 실행된다.
렌더링과 무관한 로직이 렌더링 과정에서 실행되기 때문에 렌더링 자체에 영향을 줘 성능 상 악영향을 끼칠 수도 있게 된다.
그래서 React에서는 이런 Side Effect를 일으키기 적절한 장소로써 useEffect hook을 제공한다.
공식 문서에서도 useEffect
를 "React의 순수한 함수적인 세계에서 명령적인 세계로의 탈출구로 생각하세요"라고 설명하고 있다.
여기서 "순수한 세계"란 렌더링(Input->output)을 뜻하고, 렌더링 이외에 일으켜야 하는 Side Effect를 일으킬 탈출구로 useEffect
를 사용하라는 의미이다.
useEffect
는 Side Effect를 렌더링 이후에 발생시킨다. (예외: useLayoutEffect
)
useEffect
가 수행되는 시점에 이미 DOM이 업데이트되었음을 보장한다는 뜻이고, 바꿔 말하면 Side Effect가 렌더링에 영향을 주지 않도록 설계되었음을 의미한다.
(Open Sandbox를 누르거나 왼쪽 바를 땡기면 코드를 확인할 수 있다.)
여기 클릭하면 setCount를 작동시켜 렌더링을 시키는 버튼과, 값을 입력할 때마다 렌더링이 되는 Input이 있다.
버튼을 눌렀을 때에만 콘솔창에 카운트됨을 출력하고싶은데, input에 값을 입력할 때마다 새롭게 렌더링이 되기때문에 불필요하게 같은 값이 콘솔에 출력되게 된다.
그럴 때, Dependancy Array를 사용하면 된다.
useEffect
의 두번째 인자로 배열에 담아 넣어주게 되면, 그 값이 변경될 때에만 useEffect
의 콜백함수를 실행한다.
방금 말한대로 useEffect
에 2번째 인자로 count를 담은 배열을 넣어줬다. 그러자 +1 버튼을 누를 때에만 콘솔창에 카운트됨이 출력되고, input값을 아무리 변경해봐도 전과는 다르게 콘솔창에 아무것도 출력되지 않는다.
마지막으로 Effect 이후 일어나는 Cleanup Effect
에 대해서 알아보자.
Cleanup Effect
는 간단하게 설명하자면, 이전에 일으킨 Side Effect를 정리할 필요가 있을 때 사용한다.
이벤트 리스너 케이스를 예시로 한번 살펴보겠다.
다음 코드는 페이지에 스크롤 이벤트가 일어날 때마다 console에 현재 스크롤이 위치한 Y 좌표를 출력한다.
Side Effect이므로 useEffect
안에서 사용하고, 이벤트 리스너는 한번만 등록하면 되기 때문에 Dependency Array에는 빈 배열을 넣어주었다.
(빈 배열을 넣으면 맨 처음 마운트 될 때에만 실행된다.)
useEffect(() => {
function handleScroll() {
console.log(window.scrollY)
}
document.addEventListener("scroll", handleScroll)
}, [])
하지만 우리가 이 페이지를 벗어났을 때 이 이벤트 리스너는 더 이상 필요없어질 수 있다.
이 경우 우리가 일으켰던 Effect를 정리해줘야 한다.
이 때마다 Cleanup Effect를 일으킬 수 있도록 useEffect
안에 해당 로직을 정리하는 동작을 정의해두면 된다.
useEffect(() => {
function handleScroll() {
console.log(window.scrollY)
}
document.addEventListener("scroll", handleScroll)
return () => {
document.removeEventLisnter("scroll", handleScroll)
}
}, [])
주의할 점은 단순히 컴포넌트가 생성되고, 사라지는 시점에만 Cleanup Effect가 실행되는 건 아니라는 것이다. 다음 Effect가 일어나기 전에, 이전 Effect의 영향을 정리해줘야 한다는 컨셉을 꼭 기억하자.
😒