Side Effect
: 부작용, 부수효과.
이름만 들어서는 약간 부정적인 의미를 가진 것 같기도 하다.
하지만 함수 컴포넌트에서 Side Effect는 단순히 함수 실행시 함수 외부의 상태를 변경하는 연산을 뜻하며,
렌더링외의 함수 외부 환경에 영향을 주는 어떠한 이벤트라고 할 수 있겠다.
_ex) API 호출, Data Fetching, 이벤트 처리함수 등록 및 해제_
함수 컴포넌트의 리턴값은 UI 요소이며, 상태값과 props의 변화가 있을 때 마다 함수가 실행된다.
즉, 컴포넌트가 렌더링될 때 마다 함수 body에 있는 로직이 실행되며, 이는 렌더링과 무관한 로직이 렌더링 과정마다 실행되므로 렌더링 자체의 성능에 영향을 악영향을 줄 수 있게된다.
useEffect
는 렌더링과 무관한 Side Effect를 실행시킬 수 있게끔하는 리액트의 내장 훅이다.
useEffect를 좀더 폭넓게 활용하려면 리액트 컴포넌트의 Rendering Cycle
에 대한 이해가 필요하다.
리액트 컴포넌트의 렌더링 사이클에 따른 useEffect의 생명주기는 아래 그림과 같다.
mount
).re-render
)이 일어나게되는 경우(state
나 props
가 변경된 경우), useEffect는 두 번째 인자에 들어있는 의존성 배열을 체크한다. 위에서 언급한 것처럼 useEffect에 인자로 넘긴 배열에 따라 부수 효과 함수를 실행하거나 혹은 실행하지 않는다.unmount
).useEffect 훅 내의 함수는 부수 효과 함수라고 한다.
부수효과 함수는 렌더링 이후 호출되어 실행되어지고, 컴포넌트가 사라지기 직전에 마지막으로 호출이된다.
const Example = () => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `update count : ${count}`;
});
return (
<div>
<button onClick={() => setCount(prev => prev+1)}>push</button>
</div>
);
}
위 예제를 예로 들면 버튼을 클릭할 때마다 리렌더링이 일어나고 렌더링 이후 useEffect가 실행된다.
하지만 이런식으로 상태값 하나 바뀌었다고 매 렌더링마다 useEffect를 호출하는 것은 성능 저하를 유발한다.
const Example = () => {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
useEffect(() => {
document.title = `update count : ${count1}`;
}, [count1]); // count1의 값이 변경되었을 때만 useEffect가 실행된다.
return (
<div>
<button onClick={() => setCount1(prev => prev+1)}>count1 push</button>
<button onClick={() => setCount2(prev => prev+1)}>count2 push</button>
</div>
);
}
useEffect는 부수효과 함수 외에도 의존성 배열(dependancy array
)을 인자로 받을 수 있는데 이 경우 배열 내의 값이 바뀌는 경우만 useEffect를 실행하게 할 수 있다.
또 useEffect에 두번째 인자로 빈 배열[]
을 넣으면 컴포넌트의 첫 렌더링 이후 한번 실행되고, 다른 값의 변경이 일어나는 경우에도 실행되지 않게 할 수 있다.
useEffect는 unmount
될 때 (이전 클래스형 컴포넌트의 componentWillUnmount
와 같은) 클린 업 함수를 실행시킬 수 있도록 만들어 졌다.
const Example = () => {
const [scrollCount, setScrollCount] = useState(0)
const onScroll = () => {
setScrollCount(prev => prev + 1)
}
useEffect(() => {
document.addEventListener("scroll", onScroll)
return () => window.removeEventListener("scroll", onScroll)
}, []); // 컴포넌트가 마운트될 때 onScroll을 이벤트리스너에 등록하고, 언마운트될 때 해제한다.
return (
<div>
<p>scroll! : {scrollCount}</p>
</div>
);
}
위 예제처럼 useEffect에 인자로 넣어준 부수 효과 함수에 클린 업 함수를 반환해주면 된다.
그러면 컴포넌트가 unmount될 때 useEffect는 반환된 클린 업함수를 실행하고 컴포넌트는 화면에서 사라지게 된다.