본문 바로가기
front/vue

[vue3 공식문서 번역]Essentials.4.Computed Properties

by juniKang 2022. 4. 21.

기본 사례

템플린 안의 표현식은 매우 편리하지만, 간단한 작업을 위한 것이다. 템플릿에 너무 많은 로직을 넣는 것은 비대하고, 유지하기 어렵게 만든다. 예로, 중첩된 배열을 객체로 가지고 있다:

const author = reactive({
  name: 'Jone Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

저자가 책을 썻는지 안썻는지에 따라 다른 메세지를 보여주고 싶다.

<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>

이시점에, 템플릿은 좀 어수선하다. author.books에 계산된 값으로 동작하는 걸 깨닫기 위해 잠시 들여다 봐야만 한다. 더 중요한 것은, 만약 이 템플릿에서 한 번 이상 이 계산을 써야 할 때, 반복하는걸 원하지 않는다는 것이다.

 

반응형 데이타가 포함하는 복잡한 로직에 computed 프로퍼티를 추천하는 이유이다. 다음은 리팩토링된 같은 예이다:

<script setup>
import { reactive, computed } from 'vue'

const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})

// a computed ref
cont publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

이제 computed 프로퍼티인 publishedBooksMessage를 선언했다. computed() 함수는 getter 함수를 넘겨야 하며, 리턴값은 computed ref이다. 일반적인 refs와 비슷하게, publishedBooksMessage.value로 계산된 결과에 접근할 수 있다. Computed refs는 또한 템플릿에서 자동으로 언래핑되서, 템플릿안에서 .value없이 참조할 수 있다.

 

computed 프로퍼티는 반응형 의존성들을 자동으로 추적한다. 뷰는 author.books에 의존하는 publishedBooksMesage의 계산값을 신경쓰고 있어서, author.books가 바꼈을 때, publishedBooksMessage에 의존하는 모든 바인딩이 업데이트 된다.

 

Computed 캐싱 vs 메소드

표현식에서 메소드를 호출하는 것으로 같은 결과를 이룰수 있다는걸 알아차렸을 것이다.

<p>{{ calculateBooksMessage() }}</p>
// in component
function calculateBooksMessage() {
  return author.books.length > 0 ? 'Yes' : 'No'
}

computed 프로퍼티 대신, 메소드로 같은 함수를 정의할 수 있다. 결과로, 두개의 접근법은 완전히 똑같다. 하지만, 차이점은 computed 프로퍼티들은 그것들의 반응형 의존성에 기반을 두고 캐시되고 있다는 것이다. computed 프로퍼티는 오직 그것들의 반응형 의존성들이 변경되었을 때만 다시 계산된다. 이건 author.books가 바뀌지 않는한, 여러번의 publishedBooksMessage.에 대한 접근이 computed의 getter 함수를 다시 실행하지않고 이전에 이미 계산된 결과를 즉각적으로 리턴한다는 것이다.

 

또한 다음의 computed프로퍼티는 절대 업데이트 되지 않는데, Date.now()가 반응형 의존성이 아니기 때문이다.

const now = computed(() => Date.now())

대조적으로, 메소드 발동은 리렌더가 발생할떄는 언제든지 함수를 항상 다시 실행한다.

 

왜 우리가 캐싱이 필요할까? 많은 계산을 하고 거대한 배열 루핑을 필요로하는 비싼 computed 프로퍼티인 list를 가지고 있다고 상상해보자. 그리고 차례로 리스트에 의존하는 다른 computed 프로퍼티들이 있다. 캐싱이 없다면, 필요한 것보다 list의 getter를 훨씬 많이 실행하게 될 것이다! 캐싱을 원하지 않는 경우, 메소드 호출을 대신 사용하라.

 

적을 수 있는 Computed

Computed 프로퍼티들은 기본적으로 getter만 할쓸 수 있다. 만약 computed 프로퍼티에 새로운 값을 배정하는걸 시도하면, 런타임 에러메세지를 받을 것이다. "쓸 수 있는" cmpouted 프로퍼티가 필요한 희귀한 경우에, getter와 setter 둘 다를 제공하는 computed 프로퍼티를 만들 수 있다:

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  // getter
  get() {
    return firstName.value + ' ' + lastName.value
  }
  // setter
  set(newValue) {
    // Note: we are using destructuring assignment syntax here.
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})
</script>

이제, fullName.value = 'John Doe'가 실행될 때, setter는 호출되고, firstName과 lasteName은 맞춰서 업데이트될 것이다.

 

잘 쓰는 법

- getter는 사이드 이펙트로 부터 자유로워야 한다.

computed getter 함수는 순수한 계산에서 동작하고, 사이드 이펙트로부터 자유로워야 한다는걸 기억하라. 예를들면, computed getter 내에서 돔을 상태변화 시키거나, 비동기적인 요청을 만들지 마라! 다른 값에 기반을 둔 값을 어떻게 다룰지 선언적으로 묘사하는 걸로 computed 프로퍼티를 생각해라. comnputed 프로퍼티는 오직 게산하고 값을 리턴하는 데에만 책임이 있다. 가이드 뒷부분에서 상태변화에 대응하여 사이드이펙트를 일으키는 방법에 대해 wahtcers와 함께 논의할 것이다.

 

- 계산된 값을 변화시키는 걸 피하라

computed 프로퍼티로부터 리턴된 값은 파생 상태이다. 일시적인 스냅샷과 같이 생각해라. 매순간 소스의 상태가 변하며, 새로운 스냅샷이 만들어진다. 변화하는 스냅샷은 말도 안되니, computed의 리턴값은 read-only로 다루고 절대 변화하지말아야 한다. 대신에, 새로운 computed 리턴을 일으키는 트리거가 달린 소스 상태를 업데이트 해라.

댓글