본문 바로가기

웹/Vue

[Vue] Computed 속성에 대해서

🟩 Computed

Computed는 대상으로 정한 data() 속성 값이 변했을 때, 이를 감지하고 자동으로 다시 연산해주며,

결과 값은 저장(캐싱)을 합니다.(Watch와 비슷하지만 Computed에서 중요한 부분은 결과 값을 "저장"하는 부분입니다. 캐싱이 포인트입니다)

 

 

🟩 computed 속성은 Vue.js 컴포넌트 내에서 객체 형태로 선언됩니다.

예를 들어 다음과 같은 코드로 fullName이라는 computed 속성을 정의할 수 있습니다.

computed: {
  fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

 

🟩 computed 속성에 접근하기

computed 속성은 템플릿에서 {{ }}와 같은 보간법(interpolation)을 사용하여 접근할 수 있습니다. 위에서 정의한 fullName 속성에 접근하는 코드는 다음과 같습니다.

<p>이름: {{ fullName }}</p>

 

내부에서 사용하고 싶을 때 computed 속성은 data와 마찬가지로 this를 사용하여 접근할 수 있습니다. 예를 들어 다음과 같이 computeddata 속성을 함께 사용하여 total이라는 computed 속성을 정의할 수 있습니다.

data() {
  return {
    price: 10,
    quantity: 2
  }
},
computed: {
  total() {
    return this.price * this.quantity;
  }
}

🟩 computed 속성의 캐싱

computed 속성은 해당 데이터에 의존하는 데이터가 변경되지 않는 한 결과값을 캐싱합니다. 이를 통해 같은 연산을 반복적으로 수행하지 않아 성능을 향상시킬 수 있습니다.

예를 들어, 위의 total computed 속성 예제에서 price나 quantity가 변경될 때마다 total 속성이 다시 계산됩니다. 그러나 price나 quantity가 변경되지 않은 한 total 속성은 계산된 결과를 그대로 사용합니다. 

 

🟩 그러면 watch와 무엇이 다른가요?

computed 속성과 watch 속성은 모두 데이터의 변경을 감지하여 필요한 작업을 수행하는 기능을 제공합니다. 그러나 두 가지의 차이점이 존재합니다.

  • computed 속성은 데이터를 계산하고, watch 속성은 데이터를 감시합니다.
  • computed 속성은 템플릿에서 사용될 때마다 계산되며, watch 속성은 데이터가 변경될 때마다 작업을 수행합니다.

computed 속성은 vue 라이프 사이클의 영향을 받지 않습니다. template 내부에 선언된 computed 중에서 해당 함수와 연결된 값이 바뀔 때만 computed가 재연산이 됩니다.

watch 속성은 데이터의 변경을 감시하여 필요한 작업을 수행할 수 있지만, 같은 작업을 반복적으로 수행하므로 성능에 영향을 미칠 수 있습니다.

 

 

🟩 computed 속성의 getter와 setter

computed 속성은 기본적으로 getter 함수만을 가지고 있습니다. 그러나 필요에 따라 setter 함수를 정의하여 computed 속성을 변경할 수도 있습니다. setter 함수를 사용하는 경우, computed 속성을 변경할 때 해당 함수가 호출됩니다.

예를 들어, 다음과 같은 코드는 fullName computed 속성의 setter 함수를 정의한 예제입니다.

computed: {
  fullName: {
    get() {
      return `${this.firstName} ${this.lastName}`;
    },
    set(newValue) {
      const names = newValue.split(' ');
      this.firstName = names[0];
      this.lastName = names[names.length - 1];
    }
  }
}

setter 함수를 호출하는 방법은 다음과 같습니다.

this.fullName = 'John Doe';

위의 코드를 실행하면 fullName 속성setter 함수가 호출되어 firstName과 lastName 속성이 변경됩니다.

firstName은 John 으로 lastName은 Doe으로 변경이 되겠군요.

 

🟩 computed 사용 예제 코드

<template>
  <div>
    <p>반지름이 {{ radius }}인 원의 넓이는 {{ area }}입니다.</p>
    <p>반지름이 {{ radius }}인 원의 둘레는 {{ circumference }}입니다.</p>
    <button @click="incrementRadius">반지름 증가</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      radius: 5,
    };
  },
  computed: {
    area() {
      return Math.PI * this.radius * this.radius;
    },
    circumference() {
      return 2 * Math.PI * this.radius;
    },
  },
  methods: {
    incrementRadius() {
      this.radius++;
    },
  },
};
</script>

위 코드는 반지름을 저장하는 radius 데이터와 radius를 계산하는 area, circumference를 computed 속성에 가지고 있습니다.

 

computed 속성은 객체 형태로 선언하며, 계산될 값들을 함수 형태로 정의합니다. 예제 코드에서는 area와 circumference 함수에서 각각 원의 넓이와 둘레를 계산하여 반환하고 있습니다.

computed 속성에 접근하는 방식은 data와 마찬가지로 this 키워드를 이용하여 접근할 수 있습니다. 예제 코드에서는 area circumference를 템플릿에서 출력하고 있습니다.

버튼 클릭 시 incrementRadius 메서드가 실행되어 radius 데이터가 변경됩니다. 이 때 computed 속성 중 area와 circumference가 다시 계산되어 해당 값이 업데이트됩니다.

이처럼 computed 속성은 데이터를 미리 계산하여 캐싱함으로써 성능을 최적화할 수 있는 기능입니다.

 

🟩  데이터를 미리 계산하여 캐싱함으로써 성능을 최적화?(캐싱에 대해서)

예를 들어, 다음과 같은 Vue 컴포넌트가 있다고 가정해봅시다.

<template>
  <div>
    <p>전체 합계: {{ sum }}</p> // 첫 출력 시 연산 작업 실행
    <p>전체 합계: {{ sum }}</p> // 연산 실행 x
    <p>전체 합계: {{ sum }}</p> // 연산 실행 x
    <p>전체 합계: {{ sum }}</p> // 연산 실행 x
  </div>
</template>

<script>
export default {
  data() {
    return {
      numbers: [1, 2, 3, 4, 5],
    };
  },
  computed: {
    sum() {
      console.log('계산합니다.');
      return this.numbers.reduce((acc, cur) => acc + cur, 0);
    },
  },
};
</script>

위 컴포넌트에서 sum computed 속성은 numbers 배열의 모든 요소의 합계를 계산합니다. 그리고 이 값을 템플릿에서 사용하고 있습니다. 4번이나 반복적으로 동작하게 됩니다. 같은 반환값을 가지게 되는데 4번이나 연산하면 손해가 나겠죠?

그렇다면 연산과 결과값이 같은 것은 한번만 동작하고 결과값만 반환하면 되겠네요? 네, 그것이 바로 캐싱입니다.computed를 통해 만든 데이터는 캐싱을통해 한 번 연산해놓은 값을 반복적으로 출력할 때 다시 연산하지 않습니다. 왜냐하면 캐싱되어 있는값 그대로 화면에 출력하기 때문입니다.

 

 

 

🟥 인자를 받지 않는 computed

<div>{{ reverseMessage(false) }}</div>
 
computed: {
  reverseMessage(isReversed) {
    return isReversed ? this.message.split('').reverse().join('') : this.message;
  }
}
    

위의 코드는 정상적으로 동작하지 않습니다. 템플릿에 선언한 컴퓨티드 속성에 괄호가 생기는 순간 해당 템플릿을 실제 DOM으로 변환할 때 라이브러리에서 에러를 발생시킵니다.

 

🟥 HTTP 통신 코드를 제외하는 computed

data: {
  message: ''
},
computed: {
  reverseMessage() {
    axios.get('/').then((response) => {
      this.message = response.data;
    });
    return this.message.split('').reverse().join('');
  }
}
 

컴퓨티드 속성에 HTTP 요청과 같은 오래걸리는 코드를 넣는 경우가 있습니다. 기본적으로 컴퓨티드 속성은 템플릿 코드의 가독성을 위한 기능이며 HTTP 통신과 같이 브라우저 리소스가 많이 할애되는 코드들은 watch나 methods에 넣는 것이 적합합니다.

 

 

참고

728x90