[Vue 빠른시작] Lifecycle Hooks 예제 추가

[Vue 빠른시작] Lifecycle Hooks 예제 추가

각 Vue 컴포넌트 인스턴스는 생성될 때 일련의 초기화 단계를 거친다. 예를 들어 데이터 감시를 설정하고, 템플릿을 컴파일하고, 인스턴스를 DOM에 마운트하고 데이터가 변경되면 DOM을 업데이트해야 한다. 그 과정에서 생명 주기 훅(lifecycle hooks)이라 불리는 함수도 실행하여, 특정 단계에서 개발자가 의도하는 로직이 실행될 수 있도록 한다.



1. Registering Lifecycle Hooks

예를 들어 mounted 훅은 컴포넌트가 초기 렌더링 및 DOM 노드 생성이 완료된 후 코드를 실행하는 데 사용할 수 있다.

<script>
export default{
  data() {
    return {
      msg: '안녕!'
    }
  },
  mounted() {
    console.log('컴포넌트가 마운트 되었습니다.');
  }
};
</script>

<template>
  <div>{{ msg }}</div>
</template>

인스턴스 생명 주기의 여러 단계에서 호출되는 다른 훅도 있으며, 가장 일반적으로 사용되는 것은 mounted, updated, unmounted가 있다.

모든 생명 주기 훅은 호출하는 현재 활성 인스턴스를 가리키는 this 컨텍스로 호출된다. 생명 주기 훅을 선언할 때 화살표 함수를 사용해선 안되다는 것을 의미한다. 그렇지 않으면 this를 통해 컴포넌트 인스턴스에 접근할 수 없기 때문이다.



2. Lifecycle Diagram

다음은 인스턴스 생명 주기에 대한 표이다.

Options API의 옵션 함수와 컴포지션 함수의 상관관계 및 각 생명주기에 관련된 설명은 다음과 같다.


beforeCreate

컴포넌트를 생성하기 전에 호출된다. 컴포지션 API의 setup 함수 그 자체가 beforeCreate를 대체한다. 컴포넌트가 생성되기 전에 호출이 되기 때문에 생성한 data는 물론, 해당 data를 관찰할 수 있는 watch와 같은 함수들이 동작하지 않는다. setup 함수 내 작성하는 모든 코드는 beforeCreate를 대체하므로, setup 함수 내에서 사용가능한 beforeCreate는 따로 없다.


created

컴포넌트가 생성되면 호출된다. 컴포지션 API의 setup 함수가 beforeCreate와 함께 created도 대체한다. 컴포넌트의 옵션에 접근이 가능하기 때문에 data 옵션에 선언한 데이터들을 초기화 할 때 많이 사용한다.


beforeMount(onBeforeMount)

Vue의 가상 노드가 render 함수를 호출하기 직전에 호출된다. 즉, 실제 DOM을 구성하기 직전에 호출된다. 이 beforeMount 사이클이 지나고나면 Vue는 Virtual DOM에 가상으로 Rendering 할 DOM을 미리 구성한다. 이 과정은 onRenderTracked라는 생명주기 훅을 통해 관찰할 수 있다.


mounted(onMounted)

실제로 컴포넌트의 구성요소들이 DOM 엘리먼트로 마운트된 후 호출된다. 이 순간부터 실제 엘리먼트를 참조할 수 있다. 다시 말해, ref와 같은 함수를 통해 엘리먼트의 참조변수를 만들었다면, mounted 사이클 이전까지는 초기화한 값으로만 들어있고, 실제 엘리먼트를 참조 할 수 없던 반면, 지금부터는 해당 변수를 통해 엘리먼트에 접근할 수 있게 되는 것이다. 따라서 실제 엘리먼트에 동적으로 변화를 줘야 할 경우 이 함수에서 처리하면 좋다. 실제 엘리먼트를 참조한다는것은 Virtual DOM이 실제 DOM에 반영이 되었음을 의미한다. 따라서 onRenderTriggered라는 생명주기 훅이 이후 호출되게 된다.


beforeUpdate(onBeforeUpdated)

데이터가 변경되었지만 아직 DOM에 반영되지 않았을 때 호출된다. 이미 DOM을 구성하는 요소가 있는데, Virtual DOM이 수정되고 이 수정사항이 DOM에 반영되기 직전에 호출되는 것이다. 아직 변경사항이 DOM에 반영되지 않았으므로, 실제 엘리먼트를 참조하는 변수로부터 아무것도 얻을 수 없다.


updated(onUpdated)

데이터가 변경되어 DOM이 변경완료된 시점에 호출된다. 따라서 이 순간부터는 DOM이 업데이트되었다고 보고, 해당 DOM에 참조된 변수를 이용해 다양한 역할을 수행할 수 있다. 주의할 점은 해당 엘리먼트의 자식 노드들이 업데이트가 완료되었다고 보장하지 않는다는 것이다. 즉, 현재 컴포넌트만 수정이 되었음을 보장하는것이다. 따라서 자식 컴포넌트까지 모두 수정된 것을 기다리기 위해서는 nextTick을 이용해 모든 자식의 업데이트가 완료되었음을 기다려야 한다.

updated() {
  this.$nextTick(function() {
    // 모든 자식이 업데이트 되었다.
  })
}

beforeUnmount(onBeforeUnmount)

컴포넌트가 탈찰되기 직전에 호출된다. 아직 모든 기능을 사용할 수 있는 상태이므로, 명시적으로 컴포넌트가 Unmount되기 전에 해줘야 할 것들을 작성하면 좋다.


unmounted(onUnmounted)

컴포넌트가 탈착되고 나서 호출된다. 이 순간부터 모든 디렉티브와 이벤트가 사용이 불가능해진다.


activated(onActivated)

keep-alive 태그는 컴포넌트가 다시 렌더링되는 것을 방지하고, 상태를 유지하기 위해 쓰인다. v-is 디렉티브가 컴포넌트를 변경할 때 기존 컴포넌트의 상태가 사라지지 않게 하기 위해 사용한다.이러한 keep-alive 태그로 컴포넌트 상태가 보존되기 시작하면 onActtivated 생명주기 훅 함수가 호출된다.

<keep-alive>
  <component v-is="currentComponent" />
</keep-alive>

deactivated(onDeactivated)

keep-alive로 상태가 유지되던 컴포넌트가 효력을 상실하면 호출된다. 소스코드를 수정한 후 저장하면 Vite의 HMR이 해당 컴포넌트를 다시 렌더링하게 되는데, 이 때 keep-alive로 activated된 컴포넌트에 deactivated가 호출됨을 확인할 수 있다.


renderTracked(onRenderTracked)

Virtual DOM이 변경될 때마다 관찰을 목적으로 해당 생명주기 훅이 호출된다. 이 함수를 통해서 DebuggerEvent 객체를 살펴보면 어떠한 이유로 Virtual DOM이 변경이 되는지 알 수 있다. DebuggerEvent는 target이란 속성을 통해서 Virtual DOM을 변경시키는 것을 추적할 수 있다.

renderTracked(e) {
  console.log(e.target)
}

renderTriggered(onRenderTriggered)

Virtual DOM이 DOM으로 바녕ㅇ이 되어야 할 때 호출된다. 따라서 onMounted, onActivated, onUpdated와 같이 실제 DOM이 변경되기 직전에 호출됨을 알 수 있다. 어떠한 이유로 렌더링이 호출되었는지 파악하기 위해서는 onRenderTracked와 마찬가지로 DebuggerEvent를 살펴보면 된다. 예를 들어, 새로운 값이 추가되어 렌더링이 다시 되어야 한다면, DebuggerEvent의 type 속성에는 'add', newValue 속성에 변화를 일으킨 새로운 값이 들어있을 것이다.


errorCaptured(onErrorCaptured)

자손 컴포넌트에 에러가 발생하면 어느 컴포넌트에서 어떤 에러가 발생했는지 알려준다. 실제 동작 중에 이러한 에러가 발생하면 안되기에 일반적으로 개발 중 에러를 캡쳐하기 위해 사용한다.




참고

Vue Docs

참고 서적