
프로그래밍을 하다보면 어떤 값에 대한 표현이 너무 길어서 변수로 따로 저장을 할 때가 있습니다. 컴포넌트 데이터도 마찬가지로 특정 조건이나 상황에 따라 길게 표현되는 데이터가 나올 수 있는데요. data 값을 하나 더 만들어서 저장할 수도 있겠지만 computed
속성을 사용하면 더 편리합니다.
computed
computed
는 data, methods와 마찬가지로 컴포넌트의 속성 중 하나입니다.
아주 긴 값
만약 어떤 data에 다음과 같은 값이 있다고 해보겠습니다.
export default {
data() {
return {
players: [
{
name: "Faker",
lane: "Mid",
career: [2013, 2015, 2016, 2017],
},
// ...
]
}
}
}
players 중에서 career가 3개 이상인 첫 번째 값을 찾아 King + 이름라는 글자가 나타나게 하고 싶습니다. 그러면 다음과 같이 긴 표현식이 나오게 되는데요.
<template>
<div>
{{ players.filter((p) => p.career.length > 3)[0].name + " King" }}
</div>
</template>
가독성도 좋지 않고 나중에 코드를 다시보면 “이게 뭐지?” 하는 순간이 올 수 있습니다.
methods로 대체하면
이 긴 값을 methods을 사용해서 함수로 만들면 줄일 수 있을 것 같습니다.
<template>
<div>
{{ whoIsKing() }}
</div>
</template>
export default {
data() {
// ...
},
methods: {
whoIsKing() {
for (const p of this.players) {
if (p.career.length > 3) {
return p.name + " King"
}
}
}
}
}
어떤 의도로 구성된 코드인지 함수명을 보면 할 수 있고 코드 내용도 더 보기 좋아졌습니다.
그럼에도 불구하고 한 가지 문제가 발생하는데요. 만약 이 whoIsKing
을 여러 곳에서 사용한다고 해보겠습니다.
<template>
<div>
{{ whoIsKing() }}
{{ whoIsKing() }}
{{ whoIsKing() }}
{{ whoIsKing() }}
</div>
</template>
이를 렌더링하기 위해 함수가 4번 실행됩니다. 만약 players
의 개수가 10000개라면 10000개의 반복문이 4번 실행되는 것이 되겠죠.
computed의 등장
이러한 단점을 줄이기 위해 computed 속성이 등장합니다. 사용법도 methods랑 크게 다르지 않습니다. 함수를 정의하고 사용하고 싶은 값을 반환해주면 됩니다.
export default {
data() {
// ...
},
computed: {
whoIsKing() {
for (const p of this.players) {
if (p.career.length > 3) {
return p.name + " King"
}
}
}
}
}
다만 computed에서 반환된 값은 데이터처럼 다루기 때문에 methods 방식과 달리 괄호(()
)가 들어가지 않습니다.
<template>
<div>
{{ whoIsKing }}
</div>
</template>
결국 methods와 동일한 것 같지만, 다른 점은 캐싱(caching)을 한다는 것입니다. computed는 사용된 데이터 값이 업데이트 될 때까지는 기존의 값을 재활용합니다. 한 번 계산되면(computed) 그 뒤로 몇 번을 부르던 간에 똑같은 값을 사용한다는 뜻입니다.
업데이트 되지 않는 경우
computed은 사용된 모든 값이 아니라 반응형 의존성(reacitve dependency)들만 보고 업데이트합니다. 여기서 말하는 반응형 의존성은 Vue가 변했는지 알 수 있는 값들을 말하는데요. data
에 있는 값이나 이후에 다룰 Vuex의 state
가 있습니다.
그래서 다음과 같이 단순한 값은 처음 계산된 이후 업데이트 되지 않습니다.
computed: {
now() {
return Date.now()
}
}
computed 를 수동 업데이트
computed로 만들어진 값은 기본적으로 변경시킬 수 없지만 get
, set
을 사용하면 가능합니다.
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
// 이름을 띄어쓰기로 분리
[this.firstName, this.lastName] = newValue.split(' ')
}
}
}
}
get
함수: 읽을 때 이 값을 사용합니다.set
함수: 값을 쓸 때 사용합니다.마무리하며
computed
를 이용하면 가독성을 높일 뿐만 아니라 성능도 끌어올릴 수 있습니다. 위에서 값을 변화 시킬 수 있는 방법도 안내했지만 computed의 용도는 다른 값을 가져와서 더 단순하게 만들어 사용하는 것입니다. 그렇기에 되도록 값을 수동으로 업데이트하지 말고 내부적으로 request 요청이나 DOM을 변화시키는 등의 side-effect가 없도록 해야합니다.
computed: {
fullName() {
// BAD! computed 내에서 DOM을 바꾸는 일을 하지맙시다!
document.querySelector(".last-name").textContent = "king"
// BAD! 문제가 생길 여지가 있는 비동기 요청을 넣지맙시다!
fetch("...").then(function(){
// ...
});
}
}
물론 데이터가 바뀔 때마다 특정 처리를 하고 싶은 경우가 있을 수 있습니다. 이를 위한 속성인 watch 가 있습니다. 다음 글에서 자세히 다뤄보도록 하겠습니다!