VueJS의 Life Cycle에 대해서 알아보자
💡 새롭게 알게된 점
VueJS에서 각 Vue 컴포넌트 인스턴스는 생성될 때 데이터 감시 설정, 템플릿 컴파일, 인스턴스를 DOM에 마운트, 데이터의 변경 시 DOM을 업데이트하는 일련의 초기화 단계를 거친다.
이 과정에서 수명 주기 훅(lifecycle hooks)이라고 불리는 함수를 실행해 특정 단계에서 개발자가 의도하는 로직이 실행될 수 있도록 한다.
Lifecycle
Vue 공식 문서에 나와 있는 수명 주기 표이다. 이러한 수명 주기에 대해서 자세히 알아보자
우선 크게 beforeCreated, created, beforeMount, mounted와 beforeUpdate, updated와 beforeUnmount, unmounted 이렇게 3개로 나눌 수 있다.
beforeCreated, created, beforeMount, mounted
<div id="app"> <h1></h1> </div>
const { createApp } = Vue; const App = { data() { return { msg: 'Hello Vue!', }; }, beforeCreate() { console.log('beforeCreate!'); }, created() { console.log('created!'); }, beforeMount() { console.log('beforeMount!'); }, mounted() { console.log('mounted!'); }, }; const vm = createApp(App).mount('#app');
위 코드의 결과는 무엇일까?
당연하게도 beforeCreated, created, beforeMount, mounted의 순서대로 출력된다. 이 결과는 선언 순서를 바꾸더라도 유지된다.
그렇다면 각 상태에서 this를 통해 msg라는 data에 접근할 수 있을까? 확인해보자.
{...} beforeCreate() { console.log('beforeCreate!', this.msg); }, created() { console.log('created!', this.msg); }, beforeMount() { console.log('beforeMount!', this.msg); }, mounted() { console.log('mounted!', this.msg); }, {...}
아래에서 createApp()을 하기 전인 beforeCreate에서는 View Application이 만들어지기 직전에 실행되기 때문에, this를 통해 msg라는 data에 접근할 수 없다.
그 외의 created, beforeMount, mounted 에서는 접근할 수 있다.
그렇다면 각 주기에서 DOM에 직접 접근할 수 있을까?
{...} beforeCreate() { console.log('beforeCreate!', this.msg); console.log(document.querySelector('h1')); }, created() { console.log('created!', this.msg); console.log(document.querySelector('h1')); }, beforeMount() { console.log('beforeMount!', this.msg); console.log(document.querySelector('h1')); }, mounted() { console.log('mounted!', this.msg); console.log(document.querySelector('h1')); }, {...}
mounted를 제외한 나머지 주기에서는 html 구조와 연결되기 전이기 때문에 접근할 수 없다. 하지만 html 구조와 연결된 직후인 mounted에서는 접근할 수 있다.
beforeCreate
View Application이 만들어지기 직전에 실행된다.
아래에서 createApp()을 하기 전이기 때문에 this를 통해 msg라는 data에 접근할 수 없다.
따라서 활용도가 제일 떨어진다.
created
View Application이 만들어진 직후에 실행된다.
this를 통해 data에 접근할 수 있기 때문에 많이 사용되는 라이프 사이클
따라서 활용도가 제일 높다.
beforeMount
View Application이 실제 html 구조와 연결되기 직전에 실행된다.
created보다 느리고, mounted 처럼 html 구조를 활용할 수 있는 것도 아니기에 활용도가 떨어진다.
mounted
View Application이 실제 html 구조와 연결된 직후에 실행된다.
html 구조(DOM)와 연결된 직후 이기 때문에 여기서만 접근 가능하다.
DOM API를 다룰 수 있는 유일한 수명 주기로 created와 더불어 활용도가 제일 높다.
beforeUpdate, updated
{...} beforeUpdate() { console.log('beforeUpdate', this.msg); }, updated() { console.log('updated', this.msg); } {...}
위 코드 실행 시 이름과 유사하게 beforeUpdate는 this.msg가 업데이트 되기 전 값, updated는 업데이트 된 값이 나올까?
실제로 실행해 보면 그렇지 않다.
{...} beforeUpdate() { console.log('beforeUpdate', this.msg); console.log(document.querySelector('h1').textContent); }, updated() { console.log('updated', this.msg); console.log(document.querySelector('h1').textContent); } {...}
하지만 html의 data가 있는 곳에서는 업데이트 되기 전 값이 출력됨을 알 수 있다.
이를 통해 beforeUpdate는 data가 바뀌었을 때, 같이 바뀌는 화면이 업데이트 되기 전의 상태를 의미한다는 것을 알 수 있다.
참고로 updated 훅에서 컴포넌트 상태를 변경하면, 무한 업데이트 루프가 발생할 수 있다고 한다.
beforeUnmount, unmounted
{...} beforeUpdate() { console.log('beforeUnmount!'); }, updated() { console.log('unmounted!'); } {...} const app = createApp(App); app.unmount();
앞의 두 예제를 봤으니 이 예시 코드의 결과는 잘 알 수 있다.
❗️ 느낀점
여태까지 프레임워크를 공부할 때 라이프 사이클의 중요성을 깨닫지 못했어서 사용 중간에 찾아보는 경우가 많았었는데, 저번 인턴십때 플러터 라이프 사이클을 공부한 다음 사용하니 이해도가 훨씬 높았었던 경험이 있었다.
이를 생각해 보았을 때 Vue에 대해 자세히 공부하기 전, 라이프 사이클에 대해 먼저 공부하는 것은 충분히 도움이 될 것이라 여겨진다.
Vue는 이번이 처음이라 React와 무엇이 다르고 무엇이 비슷할지, 장단점을 비교하며 재밌게 공부할 수 있을 것 같다.