계산이 필요한 데이터를 사용할 때, 매번 그 계산을 하지 않아도 된다. computed 옵션을 사용하면 캐싱 기능으로 인해 계산된 값을 가져와 쓸 수 있다.
<div id="app">
<h1>{{count}}</h1>
<h2>{{count * 2}}</h2>
<h2>{{doubleMethod()}}</h2> // 메소드 실행으로 값 사용
<h2>{{double}}</h2> // computed된 데이터는 ()없이 사용
</div>
<script>
const App = {
data() {
return {
count: 3,
};
},
computed: {
double() { //// 이렇게 메소드로 두고
return this.count * 2;
},
},
methods: {
doubleMethod() {
return this.count * 2; //여기서 this는 App 컴포넌트
},
},
};
const vm = Vue.createApp(App).mount("#app");
</script>
예제 - 객체 데이터의 내부 속성 값 변경과 의존
반응형 데이터의 값이 변경되었을 때, 해당 데이터로 계산을 하는 computed 속성이 있으면 다시 실행된다. “의존”되어 있기 때문.
변경된 데이터로 계산을 하지 않는, 의존되어 있지 않는 속성들은 다시 실행되지 않는다!
<body>
<div id="app">
<h1>{{user.name}}</h1>
<h2>{{user.age}}</h2>
<h2>{{doubleAge}}</h2>
<h2>{{upperName}}</h2>
</div>
<script>
const App = {
data() {
return {
user: {
name: "toto",
age: 22,
email: "Asdf@ac.com",
},
};
},
computed: {
doubleAge() {
// user.age 변경시 해당 계산도 다시 일어난다. user.age에 의존해있음을 알 수 있다.
// use.name 등에는 의존하지 않는다!!!!
return this.user.age * 2;
},
upperName() {
// 마찬가지로 this.user.name에만 의존되어 있음
return this.user.name.toUpperCase();
},
},
};
const vm = Vue.createApp(App).mount("#app");
</script>
</body>
computed 속성은 기본적으로 읽기전용이다.
<body>
<div id="app">
<h1>{{fullName}}</h1>
<h2>{{firstName}}</h2>
<h2>{{lastName}}</h2>
</div>
<script>
const App = {
data() {
return {
firstName: "leon",
lastName: "miller",
};
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`;
},
},
};
const vm = Vue.createApp(App).mount("#app");
</script>
</body>
따라서, vm.firstName 이나 vm.lastName에 접근하여 변경하면 fullName도 변경된다.
하지만 반대로 vm.fullName으로 접근하면 fullName뿐 아니라 firstName과 lastName도 반영되지 않는다!
수정 가능하게 하기 위해 getter와 setter를 이용할 수 있다.
computed: {
fullName: {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(newValue) {
const names = newValue.split(" "); // 배열
this.firstName = names[0];
this.lastName = names[names.length - 1];
},
},
},
set() : 해당 데이터(fullName)을 변경하려 할 때 발생. 인자로 변경하려는 값이 들어온다.
반응형 데이터가 변경되는 것을 감시하고, 변경 시 실행할 로직을 선언한다.
data 또는 computed를 통해 선언된 속성(반응형 데이터)을 감시할 수 있다. 이 때, 해당 속성(데이터)의 이름과 동일하게 지정해야 한다!
예제 - string 데이터에 대한 감시
<body>
<div id="app">
<h1>{{fullName}}</h1>
<h2>{{firstName}}</h2>
<h2>{{lastName}}</h2>
</div>
<script>
const App = {
data() {
return {
firstName: "leon", // 반응형 데이터
lastName: "miller",
};
},
computed: {
fullName: { // computed 값또한 watch에 가능
get() {
return `${this.firstName} ${this.lastName}`;
},
set(newValue) {
const names = newValue.split(" ");
this.firstName = names[0];
this.lastName = names[names.length - 1];
},
},
},
watch: {
firstName() {
console.log("watch firstname", this.firstName);
},
fullName() { //
console.log("watch fullName", this.fullName);
},
},
};
const vm = Vue.createApp(App).mount("#app");
</script>
</body>
firstName 변경시 fullName 도 변경되기 때문에 fullName을 감시하는 watch 옵션도 동작
각 watch옵션 함수에서 첫번째 인자는 새로운데이터, 두번째 인자는 기존 데이터 !!! 순서주의
watch: {
firstName(newValue, oldValue) {
console.log("watch firstname", this.firstName);
},
객체나 배열 같은 참조형 데이터를 감시한다면, 데이터 내부 일부 변경에 대해서도 감시하기 위해 깊은 감시가 필요하다.
deep
옵션 → 옵션 사용을 위해 실행할 로직을 handler()
함수로 감싸주어야 한다.immediate
옵션watch: {
resData: {
handler() {
//
},
deep: true, // 깊은 감시 설정
immediate : true, // 변경시와는 별개로 맨처음 실행 지시
}
예제 - 객체 타입 데이터에 대한 감시
객체의 모든 중첩 속성을 탐색하기 위해선 깊은 감시
가 필요하다. 이는 deep
옵션을 사용한다.
<body>
<div id="app">
<h1>{{user.age}}</h1>
</div>
<script>
const App = {
data() {
return {
user: {
name: "leon",
age: 22,
},
};
},
watch: {
user: {
handler(newV, oldV) {
console.log(newV, oldV);
},
deep: true, ///
},
},
};
const vm = Vue.createApp(App).mount("#app");
</script>
</body>
예제 - 배열 데이터에 대한 감시
객체와 마찬가지!
<body>
<div id="app">
<h1>{{user.age}}</h1>
<button @click="capitalize">CAPITALIZE</button>
<ul>
<li v-for="fruit in fruits">{{fruit.name}}</li>
</ul>
</div>
<script>
const App = {
data() {
return {
user: {
name: "leon",
age: 22,
},
fruits: [
{ id: 1, name: "apple" },
{ id: 2, name: "banana" },
],
};
},
computed: {},
watch: {
user: {
handler(newV, oldV) {
console.log(newV, oldV);
},
deep: true,
},
fruits: {
handler() {
console.log(this.fruits);
},
deep: true, ///////////
},
},
methods: {
capitalize() {
this.fruits.forEach((fruit) => {
fruit.name = fruit.name.toUpperCase();
});
},
},
};
const vm = Vue.createApp(App).mount("#app");
</script>
</body>