반응형 기초
https://ko.vuejs.org/guide/essentials/reactivity-fundamentals.html
반응형 상태 설정
data
옵션을 사용하여 컴포넌트 반응형 상태 선언data
에서 return 한 변수들은this
로 접근해야한다.- 컴포지션 API : reactive (객체일때), ref (원시값 일때 사용)
- data에 포함하지 않고 this 에서 데이터를 선언 및 사용 할 수 있지만, 아래와 같은 warning 을 받는다.
Property "abc" was accessed during render but is not defined on instance.
메서드 선언
- 컴포넌트 인스턴스에 메서드를 추가하기 위해서는 methods 옵션을 사용
- arrow function 사용 주의 (참고2)
- 반응 상태를 변경할 시에 DOM 업데이트가 동기적이지 않으므로,
nextTick()
을 활용하여 다음 틱까지 한번만 컴포넌트가 업데이트 되도록 한다.
<script>
import { nextTick } from 'vue'
export default {
data() {
return {
count: 0
}
},
methods: {
async increment() {
this.count++
// 아직 DOM 업데이트되지 않음.
console.log(document.getElementById('counter').textContent) // 0
await nextTick()
// 이제 DOM 업데이트됨.
console.log(document.getElementById('counter').textContent) // 1
}
}
}
</script>
<template>
<button id="counter" @click="increment">{{ count }}</button>
</template>
Computed
사용 이유
- template 문법 (
{{}}
)을 복잡하게 사용하면 유지보수성이 떨어짐- 이럴 경우, 자주 사용하는 계산 하는 로직을 미리 만들어 놓을 수 있음 : computed
- 반응형 상태의 변수를 기반으로 하기 때문에, 값이 변경되면 computed의 return 값도 변경 된다.
<script>
export default {
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// 계산된 값을 반환하는 속성
publishedBooksMessage() {
// `this`는 컴포넌트 인스턴스를 가리킵니다.
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
}
</script>
<template>
<p>책을 가지고 있다:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
<br>
<p>책을 가지고 있다:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
setter 사용 가능
- 필요에 의해 setter 함수 설정 가능
// 선언부
computed: {
fullName: {
// getter 함수
get() {
return this.firstName + ' ' + this.lastName
},
// setter 함수
set(newValue) {
const names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// getter 사용
{{fullName}}
// setter 사용 - method 내에서 주로 사용
this.fullName = "토란 토마토"
computed 와 method 차이
- return 값의 차이는 없겠지만
- 캐싱 :
computed
는 내부 값의 변경이 없으면 사용부에서 아무리 사용해도 값이 변하지 않음
- 캐싱 :
클래스와 스타일 바인딩
HTML 클래스 바인딩
data() {
return {
isActive: true,
hasError: false
}
}
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }">
</div>
// 결과
<div class="static active"></div>
data() {
return {
classObject: {
active: true,
'text-danger': false
}
}
}
// 인라인일 필요 없음, data 단에서 다 만들고 template단에서 바인딩 되어 알아서 작동
<div :class="classObject"></div>
// 결과
<div class="active"></div>
//----------------------------------------------------------------------
// computed 로 미리 계산 해놓는 것도 가능
const classObject = computed(() => {
return {
active: isActive.value && !hasError.value,
'text-danger': !isActive.value && hasError.value,
};
});
스타일 바인딩
:style
에서 사용하는 컨벤션은 카멜 케이스이지만 케밥 케이스도 지원함- fontSize <-> font-size(실제 css 사용)
data() {
return {
activeColor: 'red',
fontSize: 30
}
}
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
//----------------------------------------------------------------------
// 다중으로 값을 셋팅 가능
<div :style="{ display: ['flex', '-webkit-box', '-ms-flexbox'] }"></div>
조건부 렌더링
v-if, v-else
- truthy 값을 반환 하는 경우에만 동작
falsy
: false, null, undefined, 0, '' 일 경우 false
- template 단에서도 사용가능하다는데, 나는 안됨 ㅠ
v-show
사용 하면 동일하게 template을 보여주기, 말기가 가능- v-show는 보이던 보이지 않던 무조건 렌더링 해버림
- 그와 반대로
v-if
는 lazy 렌더링으로, true 일때만 렌더링
- 그러므로, 화면전환이 잦다면
v-show
쓰기
<script>
export default {
data() {
return {
awesome: true
}
}
}
</script>
<template>
<button @click="awesome = !awesome">전환</button>
<h1 v-if="awesome">Vue는 정말 멋지죠!</h1>
<h1 v-else-if="awesome === false">아닌가요? 😢</h1>
<h1 v-else>여기로 절대 못와</h1>
</template>
목록 렌더링
v-for
- 반복문 사용
- js 문법과 같이 in 대신 of를 사용해도 됨
<script>
export default {
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }, { message: '뭐고' }, { message: '와이라노' }]
}
},
methods:{
isThird : (index)=>{
return index === 3;
}
}
}
</script>
<template>
<li v-for="(item, index) in items">
<span v-if="isThird(index)">333333</span>
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
</template>
// 결과
Parent - 0 - Foo
Parent - 1 - Bar
Parent - 2 - 뭐고
333333 Parent - 3 - 와이라노
참고 1) [JS 기초] 포인터 개념
반응형 상태의 object 가 2개 있을때, 같은 value 값을 가지고 있더라도 obj1 == obj2
를 비교하면 false가 나온다
- 주소값이 같아지면 반응형 상태의 object는 동일한 값을 가지게 되고, 변경도 함께 된다.
<script>
export default {
data() {
return {
obj1: {},
obj2: {}
}
},
mounted() {
this.obj1.k=11; // false 도출
this.obj2 = this.obj1; // true 도출
this.obj2.l=1; // true 도출
}
}
</script>
<template>
{{obj1}},{{obj2}}, {{obj1 === obj2}}
</template>
참고 2) [JS 기초] Arrow function 과 function 의 this 사용
https://codingapple.com/unit/es6-3-arrow-function-why/?gad_source=1
- 결론: arrow function의 this 는 사용부 바깥의 this 값을 그대로 사용
- function 은 사용부에 따라 this의 범위가 달라짐
var 오브젝트1 = {
함수: function () {
console.log(this);
},
};
오브젝트1.함수(); // 출력 : {함수: f} // 오브젝트1 이 출력
var 오브젝트1 = {
함수: () => {
console.log(this);
},
};
오브젝트1.함수(); // 출력 : window
참고3) for in, of 차이
- in : key에만 접근 가능,
obj[x]
로 value 접근 가능 - of : value에 접근 가능
// in
var obj = {
a: 1,
b: 2,
c: 3,
};
for (var prop in obj) {
console.log(prop, obj[prop]); // a 1, b 2, c 3
}
// of
var iterable = [10, 20, 30];
for (var value of iterable) {
console.log(value); // 10, 20, 30
}
반응형
'개발 > Vue.js' 카테고리의 다른 글
[Vue 스터디 #3] 디렉티브, 이벤트, 양방향 바인딩, Watchers (3) | 2024.11.12 |
---|---|
[Vue 스터디 #1] 컴포넌트, 환경구성, 라이프 사이클 훅, setup (1) | 2024.11.12 |