인스턴스(Instance)
Vue에서 제공하는 API와 속성으로, 뷰로 개발하기 위하여 필수적으로 생성해야 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el : '#app',
data : {
message : 'Hello Vue!'
}
});
</script>
</body>
</html>
new Vue()로 뷰 인스턴스를 생성할 때의 Vue를 생성자라고 한다. (생성자 인자에는 객체가 들어간다.)
위 예제에서는 뷰 인스턴스 옵션 속성에 el 속성과 data 속성을 사용하였다. 이 외에 template, methods, created, watch 속성 등 여러 속성들이 뷰 인스턴스 옵션 속성으로 미리 정의되어 있다.
el 속성 값을 지정해주어야 <div id="app"> 태그 안 Vue의 기능과 속성들이 유효해진다.
el 속성으로 뷰 인스턴스가 그려질 지점을 설정하는 것이다.
참고로 el 속성 값에 html이나 body를 넣는 경우 콘솔 창에 아래와 같은 경고가 발생하고, 제대로 실행되지 않는다.
[Vue warn]: Do not mount Vue to <html> or <body> - mount to normal elements instead.
상수 설정
인스턴스에서 생성된 message 값은 수정될 수 있다. 수정된 결과 값이 바로 화면에 띄워지는 것을 Vue의 반응형이라고 하는데, 만약 상수처럼 값을 변경하지 않고 사용하기 위해서는 Object.freeze()를 사용하면 된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Vue.js</title>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var obj = {
message: 'bar'
}
Object.freeze(obj);
new Vue({
el: '#app',
data: obj
});
</script>
</body>
</html>
위와 같이 data 값을 우선 변수에 저장하고, 해당 변수를 Object.freeze()의 인자로 넣어주면 message 값은 수정될 수 없다. Vue.js devtools를 사용해 수정하려고 하면 오류가 발생한다.
유효 범위
생성한 뷰 인스턴스는 파일의 처음부터 끝까지 사용할 수 있는 게 아닌, 유효 범위가 존재한다.
위 코드에서 vm 뷰 인스턴스 내 el 속성 값을 <div id="app"> 태그로 지정해주었기 때문에 vm 뷰 인스턴스는 해당 <div> 태그 내에서만 유효하다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
{{ message }}
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var vm = new Vue({
el : '#app',
data : {
message : 'Hello Vue!'
}
});
</script>
</body>
</html>
만약 이와 같이 {{ message }}를 el에서 지정한 화면 요소인 <div id="app"> 태그를 벗어난 곳에 작성한다면, 문자열 그대로 {{ message }}가 출력된다.
생성자 함수
Vue라는 이름을 가진 생성자 함수를 만든 뒤 뷰 인스턴스 생성을 하면, 생성자 함수에서 설정한 것들을 기본적으로 사용할 수 있다.
간단하게 크롬 개발자 도구 콘솔 창에서 생성자 함수를 만들어본다.
Vue() 생성자 함수를 생성하고 this.setText 값에 function()을 저장하였다.
이후 뷰 인스턴스를 생성하고, vm.setText() 사용 시 Hello Vue! 가 출력되는 걸 볼 수 있다.
라이프 사이클(Life cycle)
라이프 사이클이란 일반적으로 애플리케이션이 가지는 생명 주기이다. 크게 네 단계로 나누며 생성, 부착, 갱신, 소멸 단계가 존재한다.
뷰 인스턴스의 상태에 따라 호출할 수 있는 속성들을 라이프 사이클이라 하는데, beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed 총 8가지가 존재한다.
각 라이프 사이클 단계 사이사이에 라이프 사이클 속성이 실행된다.
인스턴스 생성과 인스턴스 부착 사이에서는 beforeCreate, created, beforeMount, mounted 단계가 실행된다.
이벤트 및 라이프 사이클을 초기화하고, 화면에 반응성을 주입한다.
el, template 속성을 확인하고, template 속성 내용이 있다면 이를 render() 함수로 변환한다.
el 속성이 있다면 $el 생성 후 el 속성 값을 대입한다. el 속성을 가진 뷰 인스턴스를 개발자 도구 콘솔 창에 출력해보면 $el: div#app과 같은 형태로 속성 내용이 출력되는 것을 확인할 수 있다.
인스턴스 부착과 인스턴스 내용 갱신 사이에서는 beforeUpdate와 updated 단계가 실행되는데, 만약 데이터가 변경되는 일이 없다면 두 단계는 실행되지 않는다.
데이터가 변경된다면 인스턴스의 데이터를 변경한 뒤 화면을 재 렌더링하고 변경된 데이터로 갱신한다.
인스턴스 내용 갱신과 인스턴스 소멸 사이에서는 beforeDestroy, destroyed 단계가 실행된다.
인스턴스에 접근이 가능해지고 컴포넌트, 인스턴스, 디렉티브 등을 모두 해제한다.
beforeCreate
인스턴스가 생성되고 나서 가장 처음으로 실행되는 라이프 사이클 단계이다.
인스턴스 옵션 속성 중 data와 methods 속성이 정의되어 있지 않고, 화면 요소에 접근할 수 없다.
Created
이때는 data와 methods 속성이 인스턴스 내에 정의되어 있다.
따라서 data 속성과 methods 속성 값에 접근하여 로직을 실행할 수 있다. 그러나 인스턴스가 화면 요소에 부착되기 전이므로 DOM 요소(화면 요소)로는 접근이 불가능하다.
컴포넌트가 생성되고 나서 실행되는 단계이므로 서버에 데이터를 요청하여 받아오는 로직을 수행하기에 적합하다.
beforeMount
본 단계에서는 template 속성에 지정한 마크업 속성을 render() 함수로 변환한다.
render() 함수는 자바스크립트로 화면의 DOM을 그리는 함수이다.
아직 el 속성에 지정한 화면 요소에 인스턴스를 부착하기 전이다.
mounted
el 속성에서 지정한 화면 요소에 인스턴스가 부착되고 나면 호출되는 단계이다.
화면 요소에 인스턴스도 부착되었고, template 속성에 정의한 화면 요소에도 접근할 수 있기 때문에 화면 요소를 제어하는 로직을 수행하기에 좋다.
화면 요소에 인스턴스가 부착되면 인스턴스에 정의한 속성들이 화면에 나타난다.
이때 나타난 값은 뷰의 반응성(Reactivity)을 제공하기 위해 $watch 속성으로 감시된다.
beforeUpdate
관찰하고 있는 데이터가 변경되면 호출되는 단계이다. 즉, 데이터가 변경되지 않으면 호출되지 않는다는 뜻이기도 하다.
가상 DOM으로 화면을 다시 그리기 전에 호출되고, 변경 예정인 새로운 데이터에 접근할 수 있다.
변경 예정인 데이터와 관련된 로직을 넣을 수 있다.
그러나 또다시 데이터를 변경하는 로직을 넣는 것은 아무런 의미가 없다. 이 단계에서 실행된 데이터를 변경하는 로직으로 인해 화면이 다시 그려지지는 않기 때문이다.
updated
데이터 변경 후 가상 DOM으로 화면을 그리고 나면 실행되는 단계이다.
데이터 변경 후 화면 요소 변경까지 완료되었기 때문에 화면 요소 제어와 관련된 로직을 추가하기에 적합하다.
본 단계에서 데이터 값을 변경하면 무한 루프에 빠질 수 있다. 무한 루프에 빠지지 않고 변경하려면 computed 또는 watch 속성을 사용하여 변경하면 된다.
데이터 값 갱신 로직은 beforeUpdate 단계에 추가하고, 변경된 데이터의 화면 요소와 관련된 로직은 updated 단계에 추가하는 게 좋다.
beforeDestroy
뷰 인스턴스가 파괴되기 직전에 호출되는 단계로, 인스턴스에 접근할 수 있으므로 뷰 인스턴스의 데이터를 삭제하기에 적합한 단계이다.
destroyed
뷰 인스턴스가 파괴되고 나서 호출되는 단계이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Vue.js</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<br />
<script>
var vm = new Vue({
el: "#app",
data: {
message: 'Hello Vue.js!'
},
beforeCreate: function() {
console.log('beforeCreate');
},
created: function() {
console.log("created");
},
mounted: function() {
console.log('mounted');
},
beforeUpdate: function() {
console.log('beforeUpdate');
},
updated: function() {
console.log('updated');
}
});
</script>
</body>
</html>
변경된 데이터가 없기 때문에 beforeUpdate 단계와 updated 단계는 실행되지 않는 것을 볼 수 있다.
beforeUpdate 단계 전에 데이터를 변경시켜본다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Vue.js</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<br />
<script>
var vm = new Vue({
el: "#app",
data: {
message: 'Hello Vue.js!'
},
beforeCreate: function() {
console.log('beforeCreate');
},
created: function() {
console.log("created");
},
mounted: function() {
console.log('mounted');
this.message = '안녕하세요 Vue.js!'
},
beforeUpdate: function() {
console.log('beforeUpdate');
},
updated: function() {
console.log('updated');
}
});
</script>
</body>
</html>
mounted 단계에서 데이터 변경 시 beforeUpdate 단계와 updated 단계가 실행된 걸 볼 수 있다.
beforeCreate 단계에서 데이터 변경하면 어차피 data 옵션 속성이 뷰 인스턴스 내 정의되어 있지 않기 때문에 데이터가 바뀌지 않는다. 따라서 beforeUpdate 단계와 updated 단계 모두 실행되지 않는다.
created 단계에서 데이터를 변경하면 화면 요소에는 변경된 데이터 값으로 출력되나 beforeUpdate와 updated 단계 모두 실행되지 않는다. 아직 화면 요소에 부착되기 전이므로 화면에서 데이터가 변경되었다고 보지 않는 것이다.