Vue 인스턴스

var app = new Vue({}) 형식으로 생성한 객체들을 Vue 인스턴스라고 부른다. 때로는 뷰모델을 의미하는 vm을 삽입해서 vue vm 인스턴스라고도 칭한다.




1. el, data computed 옵션

data 옵션은 data 옵션에 주어진 모든 속성들을 Vue 인스턴스 내부에서 직접이용되지 않고 Vue 인스턴스와 Data옵션에 주어진 객체 사이에 프록시를 두어 처리한다. 


<body>
<div id="test">
{{ name }}
</div>
<script tpye="text/javascript">
var model = {
name: "홍길동"
}
var vm = new Vue({
el: '#test',
data: model
})
</script>
</body>


data 옵션 값이 vue 인스턴스에 의해 프록시 처리되어 vm.name과 같이 사용할 수 있음을 알 수 있다. 직접 data 옵션을 통해 접근하고 싶다면 vm.$data.name과 같이 접근할 수 있다. 내장 옵션들은 모두 $식별자를 앞에 붙이고 있는데 이름 충돌을 피하기 위한 것이다.



el 옵션은 Vue 인스턴스에 연결할 HTML DOM 요소를 지정한다. 주의할 점은 여러개 요소에 지정할 수 없다는 것이다. el 옵션 값으로 '#test'와 같이 css 선택자 표현을 사용하였으므로 혹시 CSS 클래스 선택자를 사용하면 여러 HTML 요소에 Vue 인스턴스를 연결할 수 있지 않을까 생각할 수도 있지만 여러개 요소 중 첫 번째 요소에만 연결된다.

실행 도중 동적으로 Vue 인스턴스와 HTML 요소를 연결할 수 있지만, 가능하다면 el 옵션은 Vue 인스턴스를 생성할 때 미리 지정할 것을 권장한다. ( vm.$mount("#text")와 같이 $mount()를 이용해 동적 연결 가능)


computed 옵션은 지정한 값은 함수지만 Vue 인스턴스는 프록시 처리하여 마치 속성처럼 취급한다.

<body>
<div id="test">
<input type="text" v-model="num" />
<br/> 1부터 입력된 수까지의 합 : <span>{{ sum }}</span>
</div>
<script tpye="text/javascript">
var model = {
name: "홍길동"
}
var vmSum = new Vue({
el: '#test',
data: {
num: 0
},
computed: {
sum: function() {
var n = Number(this.num);
if (Number.isNaN(n) || n < 1) return 0;
return ((1 + n) * n) / 2;
}
}
})
</script>
</body>


sum은 함수인데 vmSum.sum으로 속성 접근 방식을 사용했을 때 정상 실행되는 모습을 볼 수있다. 이러한 이유로 계산형 속성(Computed Property)라고 부르는 것이다. 물론 Vue 인스턴스의 모든 옵션 저보를 다루는 $Option속성을 이용하면 실제 함수를 확인할 수있다.



계산형 속성은 읽기 전용이라 생각할 수 있지만 set메서드를 지정하면 쓰기 작업도 가능하다. (Getter / Setter)


<body>
<div id="test">
금액 : <span>{{ amount }}</span>
</div>
<script tpye="text/javascript">
var model = {
name: "홍길동"
}
var vm = new Vue({
el: '#test',
data: {
amt: 1234567
},
computed: {
amount: {
get: function() {
var s = new String("" + this.amt)
var result = ""
var num = 0
for (var i = s.length - 1; i >= 0; i--) {
result = s[i] + result
if (num % s == 2 && i !== 0)
result = "," + result
num++
}
return result;
},
set: function() {
if (typeof(amt) === "string") {
var result = parseInt(amt.replace(/,/g, ""))
if (isNaN(result)) this.amt = 0;
else this.amt = result;
} else if (typeof(amt) === "number")
this.amt = amt;
}
}
}
})
</script>
</body>


get/set method를 생성해보았다. get method는 data 속성인 amt 값을 숫자 3마리마다 쉼표를 넣어 리턴하고 문자로 변환하기 우해 String 객체를 생성한다.  set method는 문자열을 입력받으면 쉼표를 제거한 뒤 숫자 값으로 변환하여 amt 데이터 속성에 할당한다. 쉼표를 제거하기 위한 정규표현식을 사용했다.




2. Method

Vue 인스턴스에서 사용할 메서드를 등록하는 옵션이다. 등록된 메서드는 Vue 인스턴스를 이용해 직접 호출할 수도 있고, 디렉티브 표현식, 콧수염 표현식에서도 사용할 수 있다.


<body>
<div id="test">
<input type="text" v-model="num" /><br/> 1부터 입력된 수까지의 합 : <span> {{sum()}} </span>
</div>
<script tpye="text/javascript">
var model = {
name: "홍길동"
}
var vm = new Vue({
el: '#test',
data: {
amt: 1234567
},
methods: {
sum: function() {
var n = Number(this.num)
if (Number.isNaN(n) || n < 1)
return ((1 + n) * n) / 2;
}
}
})
</script>
</body>


메서드를 호출 하기 위해서는 {{ sum() }} 형식으로 호출한다. 얼핏보면 계산형 속성과 차이점을 느끼기 어렵다. 


메서드와 계산형 속성을 사용했을 때 최종적인 결과물은 같아 보이지만 내부 작동 방식에서는 차이가 있다. 계산형 속성은 종속된 값에 의한 결괏값이 캐싱된다는 점이다. 위의 예제에서는 vmSum.num이 값이라면 계산형 속성인 sum은 캐싱된 결괏값을 바로 리턴하지만 위의 sum() 메서드를 매번 실행한다는 점이다. 


computed : {
sum: function() {
console.log(Date.now())
var n = Number(this.num)
if (Number.isNaN(n) || n < 1)
return ((1 + n) * n) / 2;
}
},


위의 소스에 console.log를 이용해 시간을 확인해보면  계산된 속성을 여러 번 액세스해도 콘솔에 타임스탬프를 출력하는 코드가 실행되지 않는다. 이 실행 결과는 캐싱된 값을 출력하고 있다는 의미를 한다. 이것이 메서드와 계산형 속성의 차이점이다.


이와 같이 메서드를 사용할 것인지, 계산형 속성을 사용할 것인지 결정할 때의 고려사항 중 하나가 캐싱 여부이다.


주의할점이 있는데 바로 ECMAScript6가 제공하는 화살표 함수는 사용해서는 안된 다는것이다. 화살표 함수 내부에서는 this가 vue 인스턴스를 가리키지 않고, 전역 객체를 가리키지 때문이다. 




3. 관찰 속성

Vue.js 에서 하나의 데이터를 기반으로 다른 데이터를 변경할 필요가 있을 때 흔히 사용 할 수 있는 것으로 계산형 속성이 있다. 이외에도 관착 송성이란 것을 사용할 수 있는데 주로 긴 처리 시간이 필요한 비동기 처리에 적합하다는 특징을 가지고 있다.


<body>
<div id="example">
x : <input type="text" v-model="x" /><br/> y : <input type="text" v-model="y" /><br/>
</div>
<script tpye="text/javascript">
var model = {
name: "홍길동"
}
var vm = new Vue({
el: '#example',
data: {
x: 0,
y: 0,
sum: 0
},
watch: {
x: function(v) {
console.log("## x 변경")
var result = Number(v) + Number(this.y);
if (isNaN(result))
this.sum = 0
else
this.sum = result
},
y: function(v) {
console.log("## y 변경")
this.y = v
var result = Number(this.x) + Number(v);
if (isNaN(result))
this.sum = 0
else
this.sum = result
}
}

})
</script>
</body>



watch 옵션에 등록되는 것은 속성의 이름과 해당 속성이 변경되었을 때 호출할 함수이다. 함수는 인자를 전달받는데, 이것은 변경된 속성의 값이다. 값이 바뀔 때마다 매번 함수가 호출된다는 점이다. 이 예제는 굳이 관찰 속성을 사용하지 않아도 된다. 이런 경우라면 계산형 속성에서도 값을 출력할 수 있다. 보통 watch 옵션이 쓰일 때에는 비동기 처리를 할 때이다.


비동기 처리의 가장 대표적인 예가 외부 서버와의 통신이다. JQeury의 AJAX 기능이나 Promise 기반의 HTTP Client 기능을 수행하는 axios, fetch와 같은 라이브러리도 있다. 


관찰 속성을 이용해 연락처 검색 기능을 제공하는 비동기 요청 예제를 만들어보았다.


<html>
<head>
<meta charset="utf-8">
<title>hello vue.js</title>
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.4/fetch.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/
es6-promise.auto.min.js"></script>
</head>
<style>
#list {
width: 600px;
border: 1px solid black;
border-collapse: collapse;
}
#list td,
#list th {
border: 1px solid black;
text-align: center;
}
#list>thead>tr {
color: yellow;
background-color: purple;
}
</style>
<body>
<div id="example">
<p>
이름 : <input type="text" v-model="name"
placeholder="두자 이상 입력하세요" />
</p>
<table id="list">
<thead>
<tr>
<th>번호</th>
<th>이름</th>
<th>전화번호</th>
<th>주소</th>
</tr>
</thead>
<tbody>
<tr v-for="contact in contactlist">
<td>{{contact.no}}</td>
<td>{{contact.name}}</td>
<td>{{contact.tel}}</td>
<td>{{contact.address}}</td>
</tr>
</tbody>
</table>
<div v-show="isProcessing === true">조회중</div>
</div>
<script tpye="text/javascript">
var model = {
name: "홍길동"
}
var vm = new Vue({
el: '#example',
data: {
name: "",
isProcessing: false,
contactlist: []
},
watch: {
name: function(val) {
if (val.length >= 2)
this.fetchContacts();
else
this.contactlist = []
}
},
methods: {
fetchContacts: _.debounce(function() {
this.contactlist = []
this.isProcessing = true
var url = "http://sample.bmaster.kro.kr/
contacts_long/search/" + this.name
var vm = this
fetch(url).then(function(response) {
return response.json()
}).then(function(json) {
vm.contactlist = json
vm.isProcessing = false
}).catch(function(ex) {
console.log('parsing failed', ex)
vm.contactlist = []
vm.isProcessing = false
})
}, 300)
}
})
</script>
</body>
</html>

Vue 객체 내에 관찰자(Watcher)는 name 속성의 변화를 감지하여 함수를 호출한다. 그리고 이 함수에서 다시 두 자 이상이 입력되었다면 fetchContacts 함수를 호출한다. 타이핑을 할 때마다 매번 API를 호출 하는거슨 비효율적이므로 lodash 라이브러리의 _.debounce() 함수를 이용해 일정 시간(300ms)이 지나도록 연속적인 호출이 일어나지 않으면 실제 APIA를 요청하도록 작성했다. 


fetchContacts 메서드에서는 fetch() 함수를 이용해 이름 검색을 수행한다. fetch() 메서드의 리턴 값을 promise 객체이다. promise 객체는 비동기 처리를 위해 주로 사용하는데, fetch()가 호출되고 나서 서버로부터 응답이 오면 .then()에 전달한 함수가 호출된다. 



4. Vue Instance Life Cycle


Vue 인스턴스는 객체로 생성되고 데이터에 대한 관찰 기능을 설정하는 등의 작업을 위해 초기화를 수행한다. 그리고 이 과정에서 다양한 라이프 사이클 훅 메서드를 적용할 수 있다.



beforeCreate : Vue 인스턴스가 생성되고 데이터에 대한 관찰 기능 및 이벤트 감시자 설정 전에 호출됨

created : Vue 인스턴스가 생성된 후에 데이터에 대한 관찰기능, 계산형 속성, 메서드, 감시자 설정이 완료된 후에 호출된다.

beforeMount : 마운트가 시작되기 전에 호출됩니다.

mounted : el에 vue 인스턴스의 데이터가 마운트된 후에 호출됩니다.

beforeUpdate : 가상 DOM이 렌더링, 패치되어 전에 데이터가 변경될 때 호출됩니다. 이 훅에서 추가적인 상태 변경을 수행할 수 있다. 하지만 다시 렌더링되지 않는다.

updated : 데이터의 변경으로 가상 DOM이 다시 렌더링되고 패치된 후에 호출된다. 이 훅이 호출되었을땐 이미 컴포턴트의 DOM이 업데이트된 상태이다.

beforeDestory : Vue 인스턴스가 제거되기 전에 호출된다.

destroyed : Vue 인스턴스가 제거된 후에 호출된다. 모든 디렉티브 바인딩이 해제되고 이벤트 연결도 모두 제거 된다.

















'Vue.js' 카테고리의 다른 글

[Vue.js] Component  (0) 2018.12.18
[Vue.js] Event 처리  (0) 2018.12.17
[Vue.js] Vue instance (뷰 인스턴스)  (0) 2018.12.16
[Vue.js] computed Property (계산형 속성)  (0) 2018.12.15
[Vue.js] 기본 디렉티브  (0) 2018.12.15
vue.js 구조  (0) 2018.12.15
Posted by 루우지