🤹‍
Vue 라이프사이클 이해하기

Vue 인스턴스의 상태가 변화함에 따라, 각 상태가 어떤 특징을 가지고 있는지 알아봅니다.

Posted by 재그지그 on December 29, 2018

FrontEnd Vue


어떤 Vue 인스턴스나 컴포넌트가 생성될 때, 미리 사전에 정의된 몇 단계의 과정을 거치게 되는데 이를 라이프사이클(lifecycle)이라 합니다. 다시 말해, Vue 인스턴스가 생성된 후 우리 눈에 보여지고, 사라지기까지의 단계를 일컫는 말입니다.

공식 문서에서 다이어그램을 제공하는데 그 내용은 위와 같습니다. Vue 인스턴스는 크게 생성(create)되고, DOM에 부착(mount)되고, 업데이트(update)되며, 없어지는(destroy) 4가지 과정을 거치게 됩니다.

이 과정에서 Vue는 각각의 단계에서, Vue를 사용하는 사람들을 위해 훅(Hook)을 할 수 있도록 API를 제공합니다. 일반적으로 많이 사용하는 종류로는 beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed가 있습니다. 이제 각각의 단계가 언제 발생하며, 어떤 특징을 가지고 있는지에 대해 알아봅니다.

beforeCreate

var app = new Vue({
    el: '#app',
    data() {
        return {
            msg: 'hello';
        }
    },
    beforeCreate(function() {
        console.log(this.msg); // undefined
    })
})

이름처럼 가장 먼저 실행되는 beforeCreate훅입니다. Vue 인스턴스가 초기화 된 직후에 발생됩니다. 컴포넌트가 DOM에 추가되기도 전이어서 this.$el에 접근할 수 없습니다. 또한 data, event, watcher에도 접근하기 전이라 data, methods에도 접근할 수 없습니다.

created

var app = new Vue({
    el: '#app',
    data() {
        return {
            msg: 'hello';
        }
    },
    created(function() {
        console.log(this.msg); // hello
    })
})

created훅에서는 data를 반응형으로 추적할 수 있게 되며 computed, methods, watch 등이 활성화되어 접근이 가능하게 됩니다. 하지만 아직까지 DOM에는 추가되지 않은 상태입니다.

data에 직접 접근이 가능하기 때문에, 컴포넌트 초기에 외부에서 받아온 값들로 data를 세팅해야 하거나 이벤트 리스너를 선언해야 한다면 이 단계에서 하는 것이 가장 적절합니다.

beforeMount

var app = new Vue({
    el: '#app',
    beforeMount(function() {
        console.log('beforeMount');
    })
})

DOM에 부착하기 직전에 호출되는 beforeMount훅입니다. 이 단계 전에서 템플릿이 있는지 없는지 확인한 후 템플릿을 렌더링 한 상태이므로, 가상 DOM이 생성되어 있으나 실제 DOM에 부착되지는 않은 상태입니다.

mounted

var app = new Vue({
    el: '#app',
    mounted(function() {
        console.log('mounted');
    })
})

일반적으로 가장 많이 사용하는 mounted훅입니다. 가상 DOM의 내용이 실제 DOM에 부착되고 난 이후에 실행되므로, this.$el을 비롯한 data, computed, methods, watch 등 모든 요소에 접근이 가능합니다.

일반적인 경우에, 부모와 자식 컴포넌트 간의 mounted훅 순서는 위의 그림과 같습니다. 부모 컴포넌트의 mounted훅은 항상 자식 컴포넌트의 mounted훅 이후에 발생한다는 것을 알 수 있습니다.

var app = new Vue({
    el: '#app',
    mounted(function() {
        this.$nextTick(function() {
            // 모든 화면이 렌더링된 후 실행합니다.
        })
    })
})

하지만 자식 컴포넌트가 서버에서 비동기로 데이터를 받아오는 경우처럼, 부모의 mounted훅이 모든 자식 컴포넌트가 마운트 된 상태를 보장하지는 않습니다. 따라서 이때는 this.$nextTick을 이용한다면, 모든 화면이 렌더링 된 이후에 실행되므로 마운트 상태를 보장할 수 있습니다.

beforeUpdate

var app = new Vue({
    el: '#app',
    beforeUpdate(function() {
        console.log('beforeUpdate');
    })
})

컴포넌트에서 사용되는 data의 값이 변해서, DOM에도 그 변화를 적용시켜야 할 때가 있습니다. 이 때, 변화 직전에 호출되는 것이 바로 beforeUpdate훅입니다. 변할 값을 이용해 가상 DOM을 렌더링하기 전이지만, 이 값을 이용해 작업할 수는 있습니다. 이 훅에서 값들을 추가적으로 변화시키더라도 랜더링을 추가로 호출하지는 않습니다.

updated

var app = new Vue({
    el: '#app',
    updated(function() {
        console.log('beforeUpdate');
    })
})

가상 DOM을 렌더링 하고 실제 DOM이 변경된 이후에 호출되는 updated훅입니다. 변경된 data가 DOM에도 적용된 상태입니다. 만약 변경된 값들을 DOM을 이용해 접근하고 싶다면, updated훅이 가장 적절합니다.

다만 이 훅에서 data를 변경하는 것은 무한 루프를 일으킬 수 있으므로 이 훅에서는 데이터를 직접 바꾸어서는 안됩니다.

mounted훅과 마찬가지로, this.$nextTick을 이용해, 모든 화면이 업데이트 된 이후의 상태를 보장할 수 있습니다.

beforeDestroy

var app = new Vue({
    el: '#app',
    beforeDestroy(function() {
        console.log('beforeDestroy');
    })
})

해당 인스턴스가 해체되기 직전에 beforeDestroy훅이 호출됩니다. 아직 해체되기 이전이므로, 인스턴스는 완전하게 작동하기 때문에 모든 속성에 접근이 가능합니다. 이 단계에서는 이벤트 리스너를 해제하는 등 인스턴스가 사라지기 전에 해야할 일들을 처리하면 됩니다.

destroyed

var app = new Vue({
    el: '#app',
    destroyed(function() {
        console.log('destroyed');
    })
})

인스턴스가 해체되고 난 직후에 destroyed훅이 호출됩니다. 해체가 끝난 이후기 때문에, 인스턴스의 속성에 접근할 수 없습니다. 또한 하위 Vue 인스턴스 역시 삭제됩니다.