/ #JAVASCRIPT#VUE.JS

Vue.js: lifecycle

라이프사이클(Lifecycle)

Vue 인스턴스의 라이프사이클은 다음과 같습니다.

img45

크게 생성(Creation), 마운트(Mounting), 업데이트(Updating), 소멸(Destruction) 4가지 단계를 거치게 되며, Vue 인스턴스는 각각의 단계에서 훅(Hook)을 위한 API를 제공하고 있습니다.

생성(Creation) 단계

Vue 인스턴스가 생성될 때 제일 먼저 실행되는 단계입니다. 컴포넌트가 DOM에 바인딩 되기 전에 수행하며, 서버 렌더링 중에도 실행됩니다.

아직 컴포넌트가 DOM에 바인딩 되지 않았기 때문에 $el 프로퍼티를 통해 DOM에 접근하거나 참조할 수 없습니다.

beforeCreate

제일 먼저 실행되는 훅으로 Vue 인스턴스가 초기화 된 직후 실행됩니다. DOM에 접근할 수 없을 뿐만 아니라 데이터나 이벤트가 활성화되지 않아 접근할 수 없습니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer type="module" src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>
main.js
new Vue({
  data() {
    return {
      msg: 'hello, world!'
    }
  },
  beforeCreate() {
    console.log('beforeCredate Hook');
    console.log('msg: ' + this.msg);
  }
}).$mount('#app')

해당 코드를 작성후 콘솔창을 확인하면 msg 데이터가 undefined로 출력됩니다.

출력 결과

img46

created

Vue 인스턴스가 DOM에 바인딩되거나 View가 렌더링 되기 전에 실행되는 훅입니다. 데이터와 이벤트가 활성화되었기 때문에 해당 인스턴스의 프로퍼티를 통해 data에 접근할 수 있습니다.

main.js
new Vue({
  data() {
    return {
      msg: 'hello, world!'
    }
  },
  created() {
    console.log('created Hook');
    console.log('msg: ' + this.msg);
    console.log('$el: ' + this.$el);
  }
}).$mount('#app')

해당 코드를 작성후 콘솔창을 확인하면 데이터 모델에는 접근할수 있지만 DOM에는 접근할 수 없습니다.

출력 결과

img47

데이터를 설정하거나 이벤트 리스너를 선언해야 한다면 이 단계에서 하는 것이 적절합니다.

마운트(Mounting) 단계

Vue 인스턴스가 DOM에 바인딩되는 단계입니다. 훅이 가장 많이 사용되는 단계이며, View의 렌더링 전후로 컴포넌트에 접근할 수 있습니다.

생성 단계와 달리 서버 렌더링 중에는 훅이 실행되지 않습니다.

beforeMount

템플릿이 컴파일되고 View가 렌더링 되기 전에 실행되는 훅입니다. 템플릿이 컴파일되어 가상 DOM은 생성되었지만 실제 DOM에는 바인딩 되지 않은 상태입니다.

mounted

View가 렌더링되고 Vue 인스턴스가 DOM에 바인딩 된 이후 실행되는 훅입니다.

일반적으로 부모와 자식 컴포넌트 사이에 훅의 실행순서는 다음과 같습니다.

부모 / 자식 컴포넌트 사이의 훅 실행순서

img48

부모 컴포넌트의 템플릿이 렌더링된 이후 실제 DOM에 바인딩 하기 전에 자식 컴포넌트가 생성됩니다. 즉, 부모 컴포넌트의 beforeMounte -> 자식 컴포넌트의 beforeMounte -> 자식 컴포넌트의 mounted -> 부모 컴포넌트의 mounted 순서로 훅이 실행됩니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer type="module" src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">
    <child-component />
  </div>
</body>
</html>
main.js
import ChildComponent from "./ChildComponent.js";

new Vue({
  components: { ChildComponent },
  beforeMount() {
    console.log('parent component beforeMount hook');
  },
  mounted() {
    console.log('parent component mounted hook');
  }
}).$mount('#app')
ChildComponent.js
export default {
  template: `<div>child component</div>`,
  beforeMount() {
    console.log('child component beforeMount hook')
  },
  mounted() {
    console.log('child component mounted hook');
  }
}
출력 결과

img49

업데이트(Updating) 단계

DOM이 리렌더링되는 단계입니다. Vue 인스턴스의 데이터 모델이 변경되거나 View가 리렌더링 될 때 훅이 실행됩니다.

디버깅이나 프로파일링시 리렌더링 시기를 확인할 경우 사용하며, Vue 인스턴스의 데이터 변경을 확인할 때는 보통 computed나 watch 옵션을 사용합니다.

beforeUpdate

컴포넌트의 데이터가 변경되어 가상 DOM이 패치되고 View가 렌더링 되기전에 실행되는 훅입니다.

컴포넌트가 리렌더링 되기 전에 반응형 데이터의 신규 상태를 확인할 경우 사용합니다.

updated

View가 렌더링된 이후 실행되는 훅입니다.

mounted와 마찬가지로 부모 컴포넌트의 beforeUpdate -> 자식 컴포넌트의 beforeUpdate -> 자식 컴포넌트의 updated -> 부모 컴포넌트의 updated 순서로 훅이 실행됩니다.

index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script defer type="module" src="./main.js"></script>
  <title>Vue 연습</title>
</head>
<body>
  <div id="app">
    <child-component :num="num" @click="num++" />
  </div>
</body>
</html>
main.js
import ChildComponent from "./ChildComponent.js";

new Vue({
  components: { ChildComponent },
  data() {
    return {
      num: 0
    }
  },
  beforeUpdate() {
    console.log('parent component beforeUpdate hook');
  },
  updated() {
    console.log('parent component updated hook');
  }
}).$mount('#app')
ChildComponent.js
export default {
  template: `
    <div>
      <button @click="$emit('click')">클릭</button>
      <span>{{ num }}</span>
    </div>
  `,
  props: ['num'],
  beforeUpdate() {
    console.log('child component beforeUpdate hook')
  },
  updated() {
    console.log('child component updated hook');
  }
}

자식 컴포넌트의 버튼을 클릭하면 부모 컴포넌트로 이벤트가 전달되고, 해당 이벤트는 num 데이터를 1 증가시킵니다. 자식 컴포넌트는 num 데이터를 props로 전달받아 템플릿에 바인딩합니다.

클릭 버튼을 누르면 다음과 같은 순서로 훅이 실행되는 것을 확인할 수 있습니다.

출력 결과

img50

소멸(Destruction) 단계

Vue 인스턴스가 DOM에서 해제되는 단계입니다. DOM으로부터 이벤트 리스너 또는 구독 상태를 제거하기위해 사용합니다.

beforeDestroy

Vue 인스턴스가 DOM으로부터 바인딩이 해제되기 직전에 실행되는 훅입니다. Vue 인스턴스가 동작하고 있기 때문에 모든 속성에 접근할 수 있습니다.

destroyed

Vue 인스턴스의 바인딩이 해제된 직후에 실행되는 훅입니다. 바인딩이 해제되었기 때문에 해당 인스턴스 속성으로 접근할 수 없습니다. 또한 하위 Vue 인스턴스 역시 해제됩니다.