React 16.8 부터 추가된 Hook 중 하나인 useEffect 의 다양한 사용법에 대해 알아보겠습니다.
useEffect 의 특징
- useEffect 는 컴포넌트가 렌더링 된 후 동작합니다. 이를 이용하여 라이프 사이클처럼 동작을 제어 할 수 있습니다.(최초에 한 번은 무조건 동작합니다)
- 함수 컴포넌트 내부에서만 동작합니다. 클래스 컴포넌트 내부에서는 이용할 수 없습니다.
- useEffect 는 첫 번째인자로 async function 을 지원하지 않습니다. (하지만 사용 할 수 있습니다 예제로 알아보겠습니다)
- useEffect 는 컴포넌트가 사라지기전에 동작을 제어 할 수 있는데, 이를 이용하여 메모리 누수를 방지 할 수 있습니다.
조리법 1: 상태 감지
useEffect 는 상태의 변화를 감지합니다.
useEffect 는 첫 번째 인자로 값이 변경되었을 때 실행할 함수, 두 번째 인자로는 상태 변경을 감지하기 원하는 상태 값들을 받습니다. 만약 두 번째 인자가 빈 배열이라면 최초에 한 번만 실행됩니다.
예제)
- useEffec에게 count 라는 상태 값을 바라보도록 합니다.
- handleIncrementCount 는 count 상태 값을 1 씩 증가시킵니다.
- count 값이 변하면 useEffect 가 동작합니다.
- 0 이라는 값이 처음에 찍혔는데 useEffect 의 특징 1번에 해당합니다.
조리법 2: 라이프사이클 흉내내기
함수형 컴포넌트는 라이프사이클을 가질 수 없습니다.
useEffect 을 이용하면 함수형 컴포넌트에서도 클래스 컴포넌트의 라이프사이클과 같이 흉내를 낼 수 있습니다.
위에서 살펴본 useEffect 의 특징 1, 4번에 해당하는 내용입니다.
useEffect 의 두번째 인자가 빈 배열이면 렌더링 후 최초 1번만 실행됩니다.
- Toggle 이라는 컴포넌트는 최초에 한 번만 실행되는 useEffect 를 정의하고있습니다. 첫 진입시
Hi Toggle...
이라는 메세지를 찍습니다. - Toggle 컴포넌트의 useEffect 내부를 보시면 return function 을 정의하고있습니다. 이 함수가 Toggle 컴포넌트가 사라질 때 실행되는 함수 입니다.
Toggle 컴포넌트가 사라질 때Bye Toggle...
이라는 값이 찍히게됩니다.
조리법 3: HTTP
클래스 컴포넌트에서의 HTTP 통신은 보통 Didmount 단계 (dom 에 mount 후)에서 이루어지는 것을 볼 수 있습니다. 하지만 함수형 컴포넌트에는 Didmount 라는 라이프사이클이 없습니다. 하지만 useEffect 를 사용하면 마운트 후를 캐치 할 수 있습니다.
하지만 useEffect 의 첫 번째 인자는 async 를 허용하지 않습니다.
즉 아래와 같은 패턴은 허용되지 않습니다.
방법 1) 즉시 실행 함수를 이용한다.
아래와 같이 async function 을 즉시 실행 함수로 실행하게되면 의도한대로 동작이 가능합니다.
방법 2) 내부에 async function 을 선언한다.
이 방법을 이용하면 state 의 여부에 따라 fetch 동작을 제어하기가 조금 더 편합니다.
조리법 4: Event
useEffect 의 특성을 이용하면 이벤트 제어가 한결 수월해집니다.
첫 진입시 이벤트를 추가하고 return function 을 이용하여 이벤트를 제거하여 메모리 누수를 방지 할 수 있습니다.
조리법 5: 여러 Context 의 값을 감시하는 SPY
Custom Hook 과 useEffect 의 특징을 이용하면 스파이를 만들 수 있습니다.
상황을 예시로 들어보겠습니다.
A 라는 Context 값과 B 라는 Context 의 값이 모두 어떤 조건을 충족했을 때 로그를 찍어주어야 하는 상황이 생겼습니다.
하지만 모든 페이지에서 이런 동작이 필요하다면 어떻게 해야될까요 ?
모든 페이지에서 값을 비교하고 로그를 찍는다면 같은 코드 중복 또는 함수를 분리하더라도 관리 측면에서 힘들 수 있습니다.
logSPY 라는 Custom Hook 을 만들어서 이런 상황을 해결해보겠습니다.
먼저 Context 들을 생성해보겠습니다.
[Cart.js]
구매한 아이템을 저장할 컨텍스트입니다.
[Counter.js]
구매한 아이템 갯수를 저장합니다.
[App.js]
Provider 를 이용하여 컨텍스트를 적용합니다
[Shop.js]
Shop 에서는 값을 저장하고 저장된 값을 보여줍니다.
- radio 값을 결과 (치킨, 떡볶이 등) 를 setItem 을 이용하여 컨텍스트에 저장합니다.
- button 값에 따라 구매 갯수를 변경합니다. 변경된 값을 setCount 를 이용하여 저장합니다.
여기서 우리는 저장된 아이템과 아이템 갯수가 변경될 때 마다 변경사항을 로그에 남기고 싶습니다. 지금은 단일 페이지지만 만약 구매 페이지가 3개에 나눠져 있다고 생각해보겠습니다. 3 개의 페이지에서 모두 해당 값을 바라보고 변경사항에 따라 로그를 남기는 함수를 만들어주어야합니다.
우리는 이 작업을 spy 라는 custom hook 에게 위임합니다.
[spy.js]
스파이는 매우 단순하게 생겼습니다. 단순히 여러 컨텍스트에 접근하여 값을 모아 useEffect 의 감지 대상으로 넣습니다. 그리고 내부에서 해당 조건에 맞게 로그를 남깁니다.
이렇게 공통된 작업을 하나의 hook 으로 만들어서 처리 하면 관리 포인트가 한 곳으로 모여 관리가 수월해집니다.
[완성된 Shop.js]