본문 바로가기

React

[ React ] useEffect와 컴포넌트 생명주기

반응형

리액트에서 Hook이 등장한 이후로 함수 컴포넌트 내부에서 state와 컴포넌트의 생명주기를 다룰 수 있게 되었다. state는 'useState'라는 훅을, 컴포넌트는 생명주기는 'useEffect'라는 훅을 사용하면 된다. 이 글의 학습 목표는 'useEffect'의 작동 원리 및 순서를 상세하게 이해하는 것이다. 그럼 바로 시작해보자!

 

1. Hook Flow Diagram

 

https://github.com/donavon/hook-flow

 

사실 이 글은 위 다이어그램을 눈으로 직접 확인해보는 것에 불과하다. 위 그림과 같이 컴포넌트의 생명주기는 크게 세 단계로 나뉜다. 참고로 'Run lazy initializers'는 useState와 useReducer 호출 시점으로, 이 함수들은 Mount 시점에만 호출된다. Mount, Update, Unmount의 의미는 아래와 같다.

 

1. Mount 
컴포넌트가 페이지에 처음 렌더링 될 때

2. Update
- 부모가 re-렌더링 될 때
- state가 바뀔때
- context가 바뀔때

3. Unmount
컴포넌트가 페이지에서 사라질때

 

여기서 캐치해야할 부분은 주체가 '컴포넌트'라는 것이다. 컴포넌트가 생기고, 변하고, 없어지는 시점을 각각 Mount, Update, Unmount라고 한다. useEffect를 잘 활용하면 컴포넌트의 특정 시점에 원하는 동작을 할 수 있도록 코딩할 수 있다. 따라서 useEffect 구문을 먼저 공부해보자.

 

2. useEffect 구문

// 구문
useEffect(callback, deps)

// 예시
useEffect(() => { 
    console.log('useEffect 실행') 
    return () => { 
        console.log('clean-up')
    }
}, [state])

 

useEffect는 두 개의 인자를 가진다.

 

첫번째 인자는 콜백함수로, useEffect가 호출될 때 실행되는 함수다. 콜백함수 내부에서 반환하는 함수는 컴포넌트가 'Update' 또는 'Unmount' 될 때 실행되는 함수다.

 

두번째 인자는 배열인데, 배열 내부에 있는 변수가 변할때마다 useEffect가 실행된다. 즉, deps로 컴포넌트의 'Update' 시점을 캐치할 수 있다. deps는 useEffect에서 아주 중요한 부분인데 deps가 없을때와 있을때, 빈 배열일 때와 값이 하나라도 있을때가 어떻게 다른지 비교해보자. 

 

 

deps의 세 가지 Case

 

Case1 - deps 생략

useEffect(() => {
    console.log('useEffect(() => {})') // Line 1
    return () => {
        console.log('useEffect(() => {}) cleanup') // Line 2
    }
})

1) Callback function(Line 1) 실행시점

    - Component is mounted

    - Component is updated

 

2) Cleanup function(Line 2) 실행시점

    - Component is updated

    - Component is unmounted

 

 

Case2 - deps가 빈 배열

useEffect(() => {
    console.log('useEffect(() => {}, [])') // Line 1
    return () => {
        console.log('useEffect(() => {}, []) cleanup') // Line 2
    }
}, [])

1) Callback function(Line 1) 실행시점

    - Component is mounted

 

2) Cleanup function(Line 2) 실행시점

    - Component is unmounted

 

 

Case3 - deps에 값이 있음

useEffect(() => {
    console.log('useEffect(() => {}, [count])') // Line 1
    return () => {
        console.log('useEffect(() => {}, [count]) cleanup') // Line 2
    }
}, [count])

1) Callback function(Line 1) 실행시점

    - Component is mounted

    - count is updated

 

2) Cleanup function(Line 2) 실행시점

    - count is updated

    - Component is unmounted

 

3. 예제로 살펴보기

예제 코드는 여기서 확인할 수 있다. 클릭한 뒤에 '개발자 도구 - 콘솔창'을 열자. 코드 설명을 잠깐 하자면 우선 크게 아래와 같이 App 컴포넌트와 Child 컴포넌트가 있다. 

Child 컴포넌트는 버튼을 클릭하면 1씩 증가하는 아주 단순한 컴포넌트다. show child 체크박스를 클릭하면 Child 컴포넌트가 mount 되고, 다시 체크박스를 클릭해 선택을 해제하면 unmount 되는 형태다. 예제 코도는 어렵지 않기 때문에 설명은 생략하겠다. 이제 Child Mount, Child Update, Child Unmount 될때 각각 콘솔창에 어떻게 출력되는지 살펴보자. 그전에 처음에 봤던 'Hook Flow Diagram'을 다시 한번 보고 오는 것을 추천한다. App 컴포넌트가 Mount 되고난 이후임을 유의하자.

 

 

Child Mount

 

 

Child Update

 

 

Child Unmount

 

정리

Mount, Update, Unmount 시점에서 Render, Cleanup Effects, Run Effects 의 순서를 정리하면 아래와 같다. 

 

Mount
Render - Run Effects

Update
Render - Cleanup Effects - Run Effects

Unmount
Cleanpu Effects

 

 

 

<참조>

https://blog.bhanuteja.dev/the-lifecycle-of-react-hooks-component   

반응형