화면 모드
계산된 속성
들어가며
- 예제 코드는 Composition API 스타일과 정확한 타입 체크를 위해
<script setup lang="ts">구문을 활용하여 작성합니다. - 함수는 es6의 화살표 함수를 사용합니다.
계산된 속성을 쓰는 이유?
Vue.js로 컴포넌트를 작성하다 보면, 템플릿이 복잡해지는 경우가 종종 있습니다. 이는 데이터 조건에 따라 다양한 UI를 표시해야 할 때, 요소에 너무 많은 논리가 포함되기 때문입니다.
따라서 반응형 데이터를 포함하는 복잡한 논리의 경우, 계산된 속성을 사용하는 것이 좋습니다.
computed()
템플릿 내 표현식은 매우 편리하지만 간단한 작업을 위한 것입니다. 템플릿에 너무 많은 논리를 넣으면 비대해져 유지 관리가 어려워질 수 있습니다. 다음 예제와 같이 사용자 데이터가 있고, 템플릿에 사용자의 정보(접속 여부, 서적 수)에 따라 UI를 표시해야 할 경우:
ts
import { reactive } from 'vue'
type User = {
id: number
name: string
status: 'ONLINE' | 'OFFLINE'
books?: number
}
const users = reactive<Array<User>>([
{ id: 1, name: '홍길동', status: 'OFFLINE', books: 2 },
{ id: 2, name: '김철수', status: 'ONLINE' },
{ id: 3, name: '박영호', status: 'OFFLINE', books: 5 }
])아래와 같이 템플릿에 논리를 추가해야 합니다. 상태뿐만 아니라 객체 내부에 배열이나 더 깊은 논리적 구조가 필요한 경우 템플릿은 더욱더 복잡해집니다.
html
<template>
<ul>
<li
v-for="user in users"
:key="user.id"
:style="{ color: user.status === 'ONLINE' ? 'green' : '' }"
>
<div>{{ user.name }}</div>
<div v-show="user.books">서적 : {{ user.books }}</div>
</li>
</ul>
</template>이제 템플릿에 사용자 접속 여부를 처리하는 style 구문을 계산된 속성으로 변경해 봅시다.
ts
import { reactive, computed } from 'vue'
...
const style = computed(() => (user: User) => ({ color: user.status === 'ONLINE' ? 'green' : '' }))html
<template>
<ul>
<li v-for="user in users" :key="user.id" :style="style(user)">
<div>{{ user.name }}</div>
<div v-show="user.books">서적 : {{ user.books }}</div>
</li>
</ul>
</template>여기에서 style이라는 계산된 속성을 선언했습니다. computed() 함수에서 반환된 값은 ref와 유사하게, 계산된 결과에 style.value로 접근할 수 있습니다. ref는 템플릿에서 자동으로 언래핑되기 때문에 템플릿 표현식에서 .value 없이 참조할 수 있습니다.
계산된 속성은 내부에 의존된 반응형 값들을 자동으로 추적합니다. Vue는 style의 값이 user.status에 의존한다는 것을 알고 있으므로, user.status 변경되면 style을 바인딩해 의존하는 모든 것을 업데이트합니다.
간단히 말해, 계산된 속성은 읽기 전용인 반응형 속성이라고 볼 수 있습니다.
더 나아가 SFC (Single File Component)의 장점을 이용하여 스타일을 추가로 지정해 봅시다.
ts
const style = computed(() => (user: User) => ({ color: user.status === 'ONLINE' ? 'green' : '' }))
const onlineClass = computed(() => (user: User) => (user.status === 'ONLINE' ? 'online' : '')) 이제 계산된 속성인 onlineClass는 style 객체를 반환하는 대신 online이라는 스타일 클래스명을 반환합니다. .online 스타일도 추가해 줍니다.
css
.online {
color: green;
}사용자 정보가 아래와 같이 표시됩니다.
전체소스:
vue
<script setup lang="ts">
import { reactive, computed } from "vue";
type User = {
id: number;
name: string;
status: "ONLINE" | "OFFLINE";
books?: number;
};
const users = reactive<Array<User>>([
{ id: 1, name: "홍길동", status: "OFFLINE", books: 2 },
{ id: 2, name: "김철수", status: "ONLINE" },
{ id: 3, name: "박영호", status: "OFFLINE", books: 5 },
]);
const onlineClass = computed(
() => (user: User) => user.status === "ONLINE" ? "online" : ""
);
</script>
<template>
<ul>
<li v-for="user in users" :key="user.id" :class="onlineClass(user)">
<div>{{ user.name }}</div>
<div v-show="user.books">서적 : {{ user.books }}</div>
</li>
</ul>
</template>
<style scoped>
.online {
color: green;
}
</style>