이번 시간에는 라이프사이클을 대체하는 훅인 useEffect에 대해서 알아보겠습니다.
class 컴포넌트 때는 라이프사이클이 컴포넌트에 중심이 맞춰져 있었습니다. 클래스가 마운트 되려할 때(componentWillMount), 마운트 되고 나서(componentDidMount), 업데이트 되었을 때(componentDidUpdate), 언마운트(componentWillUnmount) 될 때 실행됐죠.
함수 컴포넌트에서는 조금 다르게 적용합니다. 특정 데이터에 대해서 라이프사이클이 진행됩니다. 데이터는 여러 개일 수 있으므로, 클래스 컴포넌트에서는 componentWillMount, componentDidMount, componentDidUpdate, componentWillUnmount를 컴포넌트 당 한 번씩만 사용했다면, useEffect는 데이터의 개수에 따라 여러 번 사용하게 됩니다.
예를 들어 hidden이라는 state가 있다고 칩시다. hidden이 바뀌는 것에 따라서 라이프사이클을 정할 수 있습니다.
useEffect(() => {
console.log('hidden changed');
}, [hidden]);
위 코드는 컴포넌트가 첫 렌더링될 때 한 번 실행되고, 그 다음부터는 hidden이 바뀔 때마다 실행됩니다. 즉, componentDidMount와 componentDidUpdate가 합쳐진 셈입니다.
componentWillUnmount의 역할도 담당할 수가 있는데요. return으로 함수를 제공하면 됩니다.
useEffect(() => {
console.log('hidden changed');
return () => {
console.log('hidden이 바뀔 예정입니다.');
};
}, [hidden]);
데이터의 라이프 사이클이 하나로 합쳐진 셈입니다. 이것을 활용해 setTimeout한 것을 return에서 clearTimeout할 수도 있습니다.
데이터가 여러 개라면 각각의 데이터에 useEffect를 적용하면 됩니다.
useEffect(() => {
console.log('hidden changed');
}, [hidden]);
useEffect(() => {
console.log('shown changed');
}, [shown]);
componentWillMount와 componentWillUpdate는 없어졌으므로 useEffect에 해당하는 것은 없습니다.
특수한 경우도 살펴봅시다.
마운트 될 때 처음 한 번만 실행하고 싶다면 빈 배열을 넣어주면 됩니다. deps가 없어서 변경되는 것이 없으므로 처음 한 번만 실행되고 나서 다시는 재실행 될 일이 없습니다. 단, 컴포넌트가 언마운트될 때는 return의 함수가 실행됩니다.
useEffect(() => {
console.log('mounted');
return () => {
console.log('unmount');
}
}, []);
반대로 컴포넌트가 리렌더링 될 때마다 실행하게 할 수도 있습니다. 두 번째 배열을 아예 안 넣으면 데이터와 관련 없이 리렌더링 시마다 실행됩니다.
useEffect(() => {
console.log('rerendered!');
});
만약 componentDidUpdate의 역할만 하고 싶다면 어떻게 할까요? useEffect는 기본적으로 componentDidMount와 componentDidUpdate의 역할을 동시에 수행하므로 componentDidMount의 역할을 제거(또는 무시)해야 합니다. 이를 위해서는 useRef라는 훅이 필요합니다.
다음 시간에 알아봅시다!