본문 바로가기
학습/Vue.js

computed vs watch vs method

코동이 2024. 6. 12.

*개요

data, computed, watch 사용의 차이를 알아봅니다.

 

 

추가사항

  • (2024-10-23) 매개변수가 전달되는 경우에는 computed 캐싱 기능을 활용 못하므로 methods 사용

 

computed vs method


 

 computed: {
    // a computed getter
    reversedMessage: function () {
      // `this` points to the vm instance
      return this.message.split('').reverse().join('')
    }
  }
  
  methods: {
  reverseMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

 

 computed의 경우, 반응적 의존성을 기반으로 값을 캐싱합니다. 반응적 의존성이 변화되는 경우에만 computed 값이 변화합니다. 만약 this.message가 변화하면 computed의 reversedMessage도 변합니다. computed가 getter의 역할을 함으로 부작용도 없으며 의존 관계를 선언형으로 드러내어 테스트하고 이해하기 쉬 효과가 있습니다.

 

 methods의 경우, computed와 똑같이 정의할 수 있지만 캐싱 할 수 없습니다. 캐싱이 없다면, 만약 엄청나게 큰 배열 순회나 많은 연산을 수행해야 하는 경우 매번 엄청난 자원을 소모해야 합니다. 

 

 하지만 매개변수를 이용해 작업한다면 computed보다는 methods를 활용하는게 좋습니다. computed는 캐싱의 효과를 위해 사용하는데 매개변수가 매번 다르기 때문에 캐싱하지 못하고 호출시마다 매번 계산을 합니다. 캐싱을 이용하지 못한다면 명시적으로 methods로 분리하는게 개발자 입장에서 훨씬 사용하기 편합니다. 또한 매개변수가 있다면 computed 문법도 조금 달라집니다.  (참고링크) 

 

computed: {
  ...mapGetters([
    'ids',
    'itemById'
  ]),
  descriptionById: function() {
    return (id) => this.itemById(id).description;
  }
}

//매개변수가 있는 경우 아래 문법은 사용할 수 없다
descriptionById: function(id) {
    return this.itemById(id).description;
  }

 

computed vs watch


 watch 옵션도 특정 데이터를 기반으로 다른 데이터를 변경시킬 때 사용할 수 있습니다. watch는 크게 2가지로 사용할 수 있습니다.

 

 

첫째로, 단순한 계산에서 명시적 작업입니다. 하지만 이 경우 선언형 작업인 computed가 더 낫습니다.

 

//watch 사용
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar',
    fullName: 'Foo Bar'
  },
  watch: {
    firstName: function (val) {
      this.fullName = val + ' ' + this.lastName
    },
    lastName: function (val) {
      this.fullName = this.firstName + ' ' + val
    }
  }
})

//computed 사용
var vm = new Vue({
  el: '#demo',
  data: {
    firstName: 'Foo',
    lastName: 'Bar'
  },
  computed: {
    fullName: function () {
      return this.firstName + ' ' + this.lastName
    }
  }
})

 

 성, 이름으로 fullName을 표현할 때, 명시적보다 선언적으로 표현할 때 훨씬 코드가 간결하며 이해하기 편합니다.

 

 

둘째로, 비동기 작업(외부 API 호출)을 하는 경우로 watch를 활용하면 좋습니다.

 

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // whenever question changes, this function will run
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
  },
  methods: {
    getAnswer: function () {
      if (this.question.indexOf('?') === -1) {
        this.answer = 'Questions usually contain a question mark. ;-)'
        return
      }
      this.answer = 'Thinking...'
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>

 

비동기 작업을 수행하거나, 실행 횟수를 제한하거나, 특정 상태를 유지하다가 결과 답을 낼 수 있는 위 작업은 computed로는 불가능하며 watch를 사용해야 가능합니다.

 

 

store의 state은 어떻게 사용?


...
data() {
	return {
    	loading: this.$store.state.loading
    }
}
...

 

 

 개인프로젝트를 하던 중, Boolean 값을 가지는 loading을 data에 선언하고, 로딩바를 키고 끌 수 있도록 하였습니다. 그런데, store의 loading을 변화시켜도 data는 loading의 true, false를 인식하지 못하며, 전혀 값이 바뀌지 않았습니다. 왜냐하면 반응적 의존성으로 변화하는 것은 computed 속성이기 때문입니다. 공식문서에 reactive dependencies를 "반응적 의존성"으로 번역했는데, 쉽게 말해 computed가 참조하는 값(store의 loading)이 변화하면 자동으로 감지하여 선언한 값(loading())이 변하는 특징을 말합니다.

 

...
computed: {
    loading() {
    	return this.$store.state.loading;
    }
}
...

 

 

 바꿔말해, store의 loading이 아무런 변화가 없으면 computed도 아무런 변화가 없습니다. 예를 들어, Date.now()가 반응적 의존성이 없기 때문에 아래 now() 값은 바뀌지 않습니다.

 

computed: {
  now() {
    return Date.now()
  }
}

 

 

 

 

*참고

https://v2.vuejs.org/v2/guide/computed.html

 

 

 

반응형