07. Computed 와 watch

Computed

연산 결과를 캐싱해주는 computed 에 대해서 알아보겠습니다.

// App.vue 

<template>
  <div id="app">
    {{ message }}
  </div>  
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      message: 'Hello Vue !!'
    }
  }
}
</script>

위 처럼 "Hello Vue !!" 라는 state 값을 뒤집어서 표현하기 위해 아래와 같이 코드를 추가하였습니다.

<template>
  <div id="app">
    {{ message }}
    <h2>뒤집힌 message</h2>
    {{ message.split("").reverse().join("") }}
  </div>  
</template>

위처럼 템플릿 영역에 연산처리를 넣을 수 있습니다. 하지만 state 또는 props 가 변경될 때마다 re-render 되기 때문에 매번 연산을 해야된다는 부담이 있습니다.

이런 부담을 줄이고자 우리는 computed 라는 것을 이용하여 연산결과를 캐싱하여 사용할 수 있습니다.

<template>
  <div id="app">
    {{ message }}
    <h2>뒤집힌 message</h2>
    {{ reversedMessage }}
  </div>  
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      message: 'Hello Vue !!'
    }
  },
  computed: {
    reversedMessage () {
      return this.message.split("").reverse().join("")
    }
  }
}
</script>

computed 는 대상(ex. message) 을 따라 연산결과가 캐싱됩니다. 대상인 message 가 변경되지 않는다면 이미 연산처리된 즉, 캐싱처리되어있는 reversedMessage 를 가져옵니다.

Method 에서도 같은 역할을 할 수 있지 않나요 ?

물론 가능합니다. 결과는 같습니다. 하지만 함수의 경우는 re-render 될 때마다 실행되기 때문에 캐싱 이득을 취할 수 없습니다.

methods: {
  reversedMessage2 () {
    return this.message.split("").reverse().join("")
  }
}

Watch

state 나 props 를 감시하고 해당 값이 변경 되었을 때의 행동을 지정할 수 있는 watch 라는 속성에 대해서 알아보겠습니다.

fistname, lastname 을 적을 수 있는 input 을 준비하고 입력된 값을 합쳐 full name 을 출력하고 싶습니다.

<template>
  <div id="app">    
    <input v-model="firstname" />
    <input v-model="lastname"/>

    <h2>full name</h2>
    <span></span>
  </div>  
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      firstname: '',
      lastname: ''
    }
  }
}
</script>

먼저 watch 를 이용하여 출력해보겠습니다.

export default {
  name: 'app',
  data () {
    return {
      firstname: '',
      lastname: ''
    }
  },
  watch: {
    firstname (val) {
      console.log('fistname', val)
    },
    lastname (val) {
      console.log('lastname', val)
    }
  }
}

watch 할 대상을 적어주고 대상의 값이 변경되었을 때의 행동을 적어줍니다.

fullname 이라는 state 값을 추가하고 watch 의 값이 바뀔 때마다 fullname 의 값을 변경하도록 하였습니다.

<template>
  <div id="app">    
    <input v-model="firstname" />
    <input v-model="lastname"/>

    <h2>full name</h2>
    <span>{{ fullname }}</span>
  </div>  
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      firstname: '',
      lastname: '',
      fullname: ''
    }
  },
  watch: {
    firstname (val) {
      this.fullname = `${val} ${this.lastname}`
    },
    lastname (val) {
      this.fullname = `${this.firstname} ${val}`
    }
  }
}
</script>

하지만 위같은 처리를 하기위해 watch 는 좋은방법이 아닙니다. computed 라는 더 좋은 친구가 있기 때문입니다.

watch 를 computed 로 변경하기

watch 로 fullname 을 만들기 위해서는 2개의 state (first, last name) 에 watch 를 해야했습니다. 하지만 아래와 같이 computed 를 이용하면 watch 를 할필요없이 대상을 바라보게 하는 것 만으로도 fullname 을 만들 수 있습니다.

fullname 이라는 state 도 필요없어집니다. 훨씬 더 보기 편하지 않나요 ? 관리 측면에서도 훨씬 좋습니다.

<template>
  <div id="app">    
    <input v-model="firstname" />
    <input v-model="lastname"/>

    <h2>full name</h2>
    <span>{{ fullname }}</span>
  </div>  
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      firstname: '',
      lastname: '',
    }
  },
  computed: {
    fullname () {
      return `${this.firstname} ${this.lastname}`
    }
  }
}
</script>

watch ?.. computed ..?

두 가지 모두 같은 결과를 내는데 그러면 어떤걸 쓰면 좋은건가요 ..? watch 는 언제 변하는지 예측이 어려울때 많이 사용됩니다. 예를 들어 비동기 통신이 있습니다. 우리가 어떤 데이터를 요청했을 때 이 값이 1초뒤에 올지 2초뒤에 올지 예측이 어려울때 그 값을 watch 를 통하여 감시하고 있다가 해당 값에 대한 응답이 왔을때 후처리를 해줄 수 있습니다.

computed 는 위에서 알아본 것처럼 복잡한 연산같은 것을 캐싱처리하기 위해 사용됩니다.

각각의 용도가 있기 때문에 잘 나누어 사용하는것이 중요합니다 :)

Last updated