Effect Hook을 통해 클래스 방식의 라이프사이클 역활을 담당
이전 포스팅에서 특정 상황에 이벤트를 발생시키는 클래스 방식의 Lifecycle에 대해 설명했다.
Hook에서는 Lifecycle이 존재하지 않지만 Effect Hook, 즉 useEffect를 통해 흉내낼수 있다.
즉 useEffect는 클래스 방식의 Lifecycle APIs를 하나로 통합한다.
useEffect는 함수, 배열 2가지의 인자를 받아 사용하는데 각각의 인자는 다음과 같이 Lifecycle의 역활을 담당한다.
첫번째 인자 함수는
componentDidMount의 역활을 담당
첫번째 인자 함수의return값은componentWillUnmount의 역활을 담당
두번째 인자 배열은componentDidUpdate의 역활을 담당
useEffect(() => {
console.log("componentDidMount!!");
return () => {
console.log("componentWillUnmount!!");
}
}, ["componentDidUpdate"]);
Hook에서의 componentDidMount는 useEffect의 첫번째 인자 함수가 담당하며 컴포넌트 최초 렌더링시 실행된다.
아래 예제를 보면 최초 렌더링 이 후 콜솔에 결과가 찍히지 않는 것을 확인할 수 있다.
import React, { useState, useEffect } from "react";
const ShoppingList = () => {
const [count, setCount] = useState(0);
const onClickBtn = () => {
setCount(count + 1);
}
useEffect(() => {
console.log("첫 랜더링!!");
}, []);
return (
<div>
<p>맛있는 사과 {count}개 구매</p>
<button onClick={onClickBtn}>+</button>
</div>
);
};
export default ShoppingList;

Hook에서의 componentWillUnmount는 useEffect의 첫번째 인자 함수의 return이 담당하며 해당 컴포넌트가 제거되기 직전 실행된다.
클래스 방식과 마찬가지로 주로 componentDidMount에서 등록한 이벤트를 삭제해주는 역활로 사용된다.
이러한 역활을 담당하는 함수를 cleanup 함수라고 부르며 만약 이벤트를 제거해주지 않는다면 컴포넌트가 리렌더링 될 때마다 새로운 이벤트가 바인딩되어 메모리 누수가 발생할 수 있다.
import React, { useState, useEffect } from "react";
const ShoppingList = () => {
const [count, setCount] = useState(0);
const onClickBtn = () => {
setCount(count + 1);
}
useEffect(() => {
console.log("첫 랜더링!!");
interval = setInterval(() => {
console.log('이벤트 발생!!');
}, 1000);
return () => {
clearInterval(interval);
}
}, []);
return (
<div>
<p>맛있는 사과 {count}개 구매</p>
<button onClick={onClickBtn}>+</button>
</div>
);
};
export default ShoppingList;
Hook에서의 componentDidUpdate는 useEffect의 두번째 인자 배열이 담당하며 특정 값이 변경되는 경우에만 실행된다.
아래 예제를 보면 최초 렌더링 이 후 state가 변경될 때마다 결과가 콘솔에 찍히는 것을 확인할 수 있다.
import React, { useState, useEffect } from "react";
const ShoppingList = () => {
const [count, setCount] = useState(0);
const onClickBtn = () => {
setCount(count + 1);
}
useEffect(() => {
console.log("count의 값은 " + count);
}, [count]);
return (
<div>
<p>맛있는 사과 {count}개 구매</p>
<button onClick={onClickBtn}>+</button>
</div>
);
};
export default ShoppingList;

UserInfo 컴포넌트는 name, age, email 총 3가지의 state로 회원의 정보를 관리한다고 가정해보겠다.
이 때 Lifecycle과 Effect Hook은 다음과 같이 각각 다른 방법으로 state를 관리한다.
import React, { useState, useEffect } from "react";
const UserInfo = () => {
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const [email, setEmail] = useState('');
return (
<div>
<p>유저의 이름 : {name}</p>
<p>유저의 나이 : {age}</p>
<p>유저의 이메일 : {email}</p>
</div>
);
};
export default UserInfo;
클래스 방식은 아래 표와 같이 하나의 Lifecycle이 모든 state를 각각 관리한다.
| name | age | ||
|---|---|---|---|
componentDidMount | --------------------> | --------------------> | --------------------> |
componentDidMount | --------------------> | --------------------> | --------------------> |
componentDidMount | --------------------> | --------------------> | --------------------> |
Effect Hook은 아래 표와 같이 각각의 state를 독립적으로 관리한다.
| name | age | ||
|---|---|---|---|
useEffect1 | useEffect1 관리 | ||
useEffect2 | useEffect2 관리 | ||
useEffect3 | useEffect3 관리 |