10 템플릿 문법 - 실전
source: categories/study/vue-beginner-lv1/vue-beginner9-01.md
10.1 watch 속성
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch</title>
</head>
<body>
<div id="app">
<button type="button" v-on:click="addNum">increase</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
methods: {
addNum: function () {
this.num++;
}
}
})
</script>
</body>
</html>
increase 버튼
을 눌렀을 때 바로바로 num
의 값이 표시되는 화면에선 올라가지않는다.(실제론 올라가지만.. Root 컴포넌트를 다시 찍으면 올라가있다)
Root 컴포넌트를 다시 누르면 값이 올라가있는 것을 볼 수 있다.
다시 위와 같이 화면에 num
값이 나오도록 data binding
을 해준 다음에 확인해보자.
위와 같이 increase 버튼
을 누를 때마다 실시간으로 바로바로 num
값이 증가되는 것을 볼 수 있습니다.
여기서 어떤걸 해볼거냐면, num이 증가될 때마다 console로 찍어보려고합니다.
위와 같이 logText
메소드를 만들고 콘솔에 changed
텍스트를 찍으려고합니다.
addNum
메소드가 실행되어 num
값이 1 증가할 때마다 logText
메소드가 실행돼서 changed 텍스트가 콘솔에 찍히게 해보도록 합시다.
그랬을 때 사용할 수 있는 속성이 바로 watch
입니다.
이 watch
라는 속성은 기본적으로 data
를 대상으로 넣을 수 있고, data
의 변화에 따라서 특정 로직을 실행할 수 있는 Vue의 속성
이라고 보시면됩니다.
watch
에 위와 같이 num
이라는 data
를 집어넣고
data
속성의 num
값이 바뀌게되면 watch
속성 안의 num
이 실행이됩니다.
그랬을 때 logText
가 실행되도록 위와 같이 정의할 수 있겠죠.
그럼 data
의 num
이 바뀔 때마다 watch
의 num
이 계속 실행이되면서 logText
를 호출합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch</title>
</head>
<body>
<div id="app">
<!-- 화면에 num 값이 나오도록 data binding을 해줍니다. -->
{{ num }}
<!-- 아래 increase 버튼을 눌렀을 때 개발자창에서 num 값이 바로바로 올라가지 않는다. (실제론 올라가지만, Root 컴포넌트를 다시 찍으면 올라가있다) -->
<button type="button" v-on:click="addNum">increase</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
// addNum 메소드가 실행되어 num 값이 1 증가할 때마다 logText 메소드가 실행돼서 changed 텍스트가 콘솔에 찍히도록 해봅시다.
// 그랬을 때 사용할 수 있는 속성이 바로 watch입니다.
// 이 watch라는 속성은 기본적으로 data를 대상으로 넣을 수 있고, data의 변화에 따라서 특정 로직을 실행할 수 있는 vue의 속성이라고 보시면됩니다.
watch: {
// 이렇게 data에 있는 num이란 속성을 집어넣고 data의 num이 바뀌게되면 아래 num에 있는 함수가 실행되게됩니다.
num: function () {
this.logText();
},
},
methods: {
addNum: function () {
this.num++;
},
// addNum 메소드가 실행되어 num 값이 1 증가할 때마다 logText 메소드가 실행돼서 changed 텍스트가 콘솔에 찍히도록 해봅시다.
logText: function () {
console.log('changed');
},
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch</title>
</head>
<body>
<div id="app">
{{ num }}
<button type="button" v-on:click="addNum">increase</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
watch: {
num: function () {
this.logText();
},
},
methods: {
addNum: function () {
this.num++;
},
logText: function () {
console.log('changed');
},
}
})
</script>
</body>
</html>
data
의 num
값이 바뀔 때마다 watch
의 num
함수가 실행되고, watch
의 num
함수가 logText
메소드를 호출하면서 위와 같이 콘솔창에 changed 텍스트가 찍힙니다.
이것이 바로 watch
속성입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch</title>
</head>
<body>
<div id="app">
<!-- 화면에 num 값이 나오도록 data binding을 해줍니다. -->
{{ num }}
<!-- 아래 increase 버튼을 눌렀을 때 개발자창에서 num 값이 바로바로 올라가지 않는다. (실제론 올라가지만, Root 컴포넌트를 다시 찍으면 올라가있다) -->
<button type="button" v-on:click="addNum">increase</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
// addNum 메소드가 실행되어 num 값이 1 증가할 때마다 logText 메소드가 실행돼서 changed 텍스트가 콘솔에 찍히도록 해봅시다.
// 그랬을 때 사용할 수 있는 속성이 바로 watch입니다.
// 이 watch라는 속성은 기본적으로 data를 대상으로 넣을 수 있고, data의 변화에 따라서 특정 로직을 실행할 수 있는 vue의 속성이라고 보시면됩니다.
// --- 그런데 아마 이전에 배운 computed 속성과 뭐가 다른거지? 라고 생각하시는 분들이 있을 수 있습니다.
// --- computed도 마찬가지로 data의 어떤 속성이 바뀌면 그 속성과 관련있는 부분이 자동 실행되면서 바뀌었습니다.
watch: {
// 이렇게 data에 있는 num이란 속성을 집어넣고 data의 num이 바뀌게되면 아래 num에 있는 함수가 실행되게됩니다.
num: function () {
this.logText();
},
},
methods: {
addNum: function () {
this.num++;
},
// addNum 메소드가 실행되어 num 값이 1 증가할 때마다 logText 메소드가 실행돼서 changed 텍스트가 콘솔에 찍히도록 해봅시다.
logText: function () {
console.log('changed');
},
}
})
</script>
</body>
</html>
아마 이전에 배운 computed 속성과함께 보통 엮어서 생각하시거나, computed와 뭐가 다른거지? 라고 생각하시는 분들이 있을 수도 있습니다.
이 다음 시간에 watch와 computed의 차이점에 대해 살펴보도록 하겠습니다.
10.2 watch 속성 vs computed 속성
- 첫번째 보실거는
data
의num
에10
이라는 값이 할당되어있다는 것입니다. -
두번째로 보실 내용은
computed
입니다.computed
엔dobleNum
이라는 함수가 정의되어있습니다.이 함수는
data
의num
이라는 속성에 2를 곱한 값을return
합니다.이
dobleNum
을 콧수염 괄호(Mustache Tag)로 화면에 표시하게됐을 때,num
에서 2배된 값을 화면에 표시하게됩니다.이렇게 자연스럽게 vue 내부적으로 계속 계산을 하는 속성이라고 보시면됩니다.
기본적으로 data의 의존성, 의존성이라고하는 것은 위
dobleNum
로직이 실행될 때, 기준이 되는 값은data
의num
값입니다. 이data
의num
값이 변할 때마다computed
의dobleNum
함수가 실행되고 굉장히 빠르게 실행된다는 장점이 있습니다. 캐싱이라던지 다른 장점도 있지만. -
세번째로 보실건
watch
입니다.이
watch
는computed
와 굉장히 비슷한 느낌입니다.watch
같은 경우도data
의num
이 바뀌었을 때 특정 로직을 실행하기 때문에computed
와 별반 차이가 없어보입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch</title>
</head>
<body>
<div id="app">
<!-- 화면에 num 값이 나오도록 data binding을 해줍니다. -->
{{ num }}
{{ doubleNum }}
<!-- 아래 increase 버튼을 눌렀을 때 개발자창에서 num 값이 바로바로 올라가지 않는다. (실제론 올라가지만, Root 컴포넌트를 다시 찍으면 올라가있다) -->
<button type="button" v-on:click="addNum">increase</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
// addNum 메소드가 실행되어 num 값이 1 증가할 때마다 logText 메소드가 실행돼서 changed 텍스트가 콘솔에 찍히도록 해봅시다.
// 그랬을 때 사용할 수 있는 속성이 바로 watch입니다.
// 이 watch라는 속성은 기본적으로 data를 대상으로 넣을 수 있고, data의 변화에 따라서 특정 로직을 실행할 수 있는 vue의 속성이라고 보시면됩니다.
// --- 그런데 아마 이전에 배운 computed 속성과 뭐가 다른거지? 라고 생각하시는 분들이 있을 수 있습니다.
// --- computed도 마찬가지로 data의 어떤 속성이 바뀌면 그 속성과 관련있는 부분이 자동 실행되면서 바뀌었습니다.
watch: {
// 이렇게 data에 있는 num이란 속성을 집어넣고 data의 num이 바뀌게되면 아래 num에 있는 함수가 실행되게됩니다.
num: function () {
this.logText();
},
// watch 같은 경우에도 data의 num이 바뀌었을 때, 특정 로직을 실행하기 때문에 computed와 별반 차이가 없어보입니다.
},
computed: {
doubleNum: function () {
// data의 의존성, 의존성이라고 하는 것은 이 doubleNum 로직이 실행될 때, 기준으로 되는 값은 data의 num 값입니다.
// 이 data의 num 값이 변할때마다 computed의 doubleNum 함수가 실행됩니다. - 굉장히 빠르게 실행된다는 장점이 있습니다. - 캐싱이라던지 다른 장점도 있습니다.
return this.num * 2;
}
},
methods: {
addNum: function () {
this.num++;
},
// addNum 메소드가 실행되어 num 값이 1 증가할 때마다 logText 메소드가 실행돼서 changed 텍스트가 콘솔에 찍히도록 해봅시다.
logText: function () {
console.log('changed');
},
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch vs computed</title>
</head>
<body>
<div id="app">
{{ num }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
computed: {
doubleNum: function () {
return this.num * 2;
}
},
watch: {
num: function (newValue) {
this.fetchUserByNumber(newValue);
}
},
methods: {
fetchUserByNumber: function (num) {
console.log(num);
}
}
})
</script>
</body>
</html>
computed
위 코드는 computed
와 watch
의 가장 기본적인 차이점을 알기위해 적어놓은 코드입니다.
computed
같은 경우는 단순한 값에 대한 계산, 특히 b-validate 라는 validation vue 라이브러리가 있는데, 그 내부적으로 구현되어있는 것들의 대부분이 computed
속성으로 구현되어있습니다.
단순한 텍스트 입력을 받아서 거기에 대한 validation 값을 계산하는 것은 computed를 많이 사용합니다.
watch
watch 같은 경우는 실제로 무거운 로직들, 매번 실행되기엔 부담스러운 그런 로직이라고 보시면됩니다.
예를 들어서 위와 같이 data
의 num
값이 수정되었을 때, this.fetchUserByNumber()
코드가 실행되도록 작성했죠?
위 코드를 실행하면 위와 같이 Root 컴포넌트
에 num
값과 doubleNum
값이 있는걸 볼 수 있습니다.
위와 같이 data
의 num
값을 증가시키면 콘솔창에 11이 찍히죠?
이 부분이 watch
에 설정한 함수입니다.
위 console.log(num);
코드 부분이 실행이 된겁니다.
위 코드를 watch
의 num
함수에서 실행했죠?
watch
의 num
에서 fetchUserByNumber
함수를 실행했습니다.
watch
의 함수들은 위와 같이 기본적으로 2가지 인자를 받습니다.
- 첫번째 인자: newValue
- 두번째 인자: oldValue
두번째 인자는 이전값이고 첫번째 인자는 갱신된 값입니다.
watch
라는게 계속 값의 변화를 추적하고 있기 때문에 이전값과 현재 갱신된 값을 모두 인자로 받을 수 있습니다.
그래서 새로 갱신된 값(첫번째 인자)을 fetchUserByNumber
의 인자값으로 넘기고 이 함수에서 인자값으로 받습니다.
그리고 그걸 console.log
로 찍은건데,
만약 받은 인자 값을 가지고 axios.get()
데이터 요청을 했다고하면, 이게 watch
의 의미에 가장 잘 맞는 사용법이라고 생각합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch vs computed</title>
</head>
<body>
<div id="app">
{{ num }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
num: 10,
},
// 아래 코드는 computed와 watch의 가장 기본적인 차이점을 알기위해 적어놓은 코드입니다.
// computed 같은 경우는 단순한 값에 대한 계산, 특히 b-validate 라는 validation vue 라이브러리가 있는데, 그 내부적으로 구현되어 있는 것들의 대부분이 computed 속성으로 구현되어있습니다.
// 단순한 텍스트 입력을 받아서 거기에 대한 validation 값을 계산하는 것은 computed를 많이 사용합니다.
computed: {
doubleNum: function () {
return this.num * 2;
}
},
// watch 같은 경우는 실제로 무거운 로직들, 매번 실행되기엔 부담스러운 그런 로직이라고 보시면됩니다.
// 예를 들어서 아래와 같이 data의 num 값이 수정되었을 때, this.fetchUserByNumber() 코드가 실행되도록 작성했죠?
// watch의 함수들은 아래와 같이 기본적으로 2가지 인자를 받습니다.
// - 첫번째 인자: newValue
// - 두번째 인자: oldValue
// 두번째 인자는 이전값이고 첫번째 인자는 갱신된 값입니다.
// watch라는게 계속 값의 변화를 추적하고 있기 때문에 이전 값과 현재 갱신된 값을 모두 인자로 받을 수 있습니다.
watch: {
num: function (newValue, oldValue) {
this.fetchUserByNumber(newValue, oldValue);
}
},
methods: {
fetchUserByNumber: function (num, old) {
console.log(num, old);
}
}
})
// 웬만하면 computed를 사용하는 것이 좋고, watch보다는 computed가 대부분의 케이스에 적합하다라고 되어있습니다.
// 실제로 서비스를 구현해보더라도 computed로도 충분히 해결 가능한데 굳이 watch를 쓰면 코드가 좀 지저분해진다는 문제점이 생기고,
// computed가 이미 캐싱이라던지 이런 내부적인 튜닝이 더 많이 되어있기 때문에 watch보다는 computed를 통해서 간단한 값들을 계산하는 것을 추천드립니다.
</script>
</body>
</html>
computed
:validation
이라던지 간단한 텍스트 연산에 사용watch
: 무거운 동작들, 특히 데이터 요청에 적합. 위와 같이methods
에 있는 내용들과 엮어주시는게 적합할듯.
위와 같이 결론을 낸 근거자료
- watch 속성과 computed 속성 차이점에 관한 공식 문서 링크
- https://vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property
공식문서에서 말하는 내용은 이겁니다.
웬만하면 computed
를 사용하는 것이 좋고, watch
보다는 computed
가 대부분의 케이스에 적합하다 라고 되어있습니다.
실제로 서비스를 구현해보더라도 computed
로도 충분히 해결 가능한데 굳이 watch
를 쓰면 코드가 좀 지저분해진다는 문제점이 생기고, computed
가 이미 캐싱이라던지 이런 내부적인 튜닝이 더 많이 되어있기 때문에 watch
보다는 computed
를 통해서 간단한 값들을 계산하는 것을 추천드립니다.
10.3 computed 속성을 이용한 클래스 코드 작성 방법
이번 시간엔 computed
를 이용한 직관적인 코드 작성에 대해 알아보도록 하겠습니다.
예시 코드로 class binding
을 해보도록하겠습니다.
computed
를 활용해서 class binding
을 어떻게 할 수 있는지 알아보도록 하겠습니다.
그냥 class binding
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch vs computed</title>
<style>
.warning {
color: red;
}
</style>
</head>
<body>
<div id="app">
<p v-bind:class="{ warning: isError }">Hello</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
isError: false,
}
})
</script>
</body>
</html>
computed 활용 class binding
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch vs computed</title>
<style>
.warning {
color: red;
}
</style>
</head>
<body>
<div id="app">
<p v-bind:class="errorTextColor">Hello</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
isError: false,
},
computed: {
errorTextColor: function () {
return this.isError ? 'warning' : null;
}
}
})
</script>
</body>
</html>
위와 같이 코드를 정리하면 템플릿 상에서 { warning: isError }
를 넣을 필요 없이 아래 인스턴스에서 더 깔끔하게 코드를 정리할 수 있다.
computed
는 이처럼 아주 유용한 속성이기 때문에 깊게 연구하셔서 사용하시면 좋을 것 같습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>단순 class binding</title>
<style>
.warning {
color: red;
}
</style>
</head>
<body>
<div id="app">
<p v-bind:class="errorTextColor">Hello</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
isError: false,
},
computed: {
errorTextColor: function () {
return this.isError ? 'warning' : null;
}
}
})
</script>
</body>
</html>