Vue3 computed 적절한 사용 방법과 watch와 차이점

제리추·2024년 1월 19일
2
post-thumbnail

🐹 들어가기 앞서

회사에서 새롭게 Vue 플랫폼 개발을 시작하며 개념 정리한다. 내가 Vue를 다시 보게 될줄 몰랐고, 오랜만에 보니 정말 새롭다 흑흑. Vue 개발이 러닝커브가 낮고 쉽다고 하지만 React에 익숙해서 그런지 쉽지 않다는걸 느끼고 있다. 그래도 새로운걸 배우는건 재밌으니 열심히 해봐야지. 이번 글은 계산된 속성인 Computed의 등장 이유와 watch와의 차이점을 알아보자.

🐹 computed 등장 이유

<template>
  <h3>computed vs watch 차이</h3>
  <p>
    {{ data.patient.filter((el) => el.hospitalizationNumber > 2000)[0].age }}
  </p>
</template>
<script setup lang="ts">
import { computed, ref, reactive } from "vue";

const data = reactive({
  patient: [
    {
      name: "김일",
      age: 20,
      hospitalizationNumber: 2134,
    },
  ],
});

위 코드를 보면 환자들의 데이터중에서 병원 넘버가 2000 이상인 첫번째 환자의 나이를 추출하고 싶은데 이렇게 데이터가 길어지게 된다면, 코드를 작성할 때는 알아 보겠지만 시간이 지나면 가독성이 좋지 않아 이 코드의 의미를 정확하게 파악하지 못하는 경우가 생긴다. 따라서 이 문제를 함수나 computed를 사용해서 해결한다.

<template>
  <h3>computed vs watch 차이</h3>
  <p>
    {{ firstPatientAge() }}
  </p>
</template>
<script setup lang="ts">
import { computed, ref, reactive } from "vue";

const data = reactive({
  patient: [
    {
      name: "김일",
      age: 20,
      hospitalizationNumber: 2134,
    },
  ],
});

const firstPatientAge = () => {
  return data.patient.filter((el) => el.hospitalizationNumber > 2000)[0].age;
};

위와 같이 할 경우 함수명을 확인한다면 개발자가 어떤 것을 출력하고 싶은지 예측이 가능하다. 그렇지만 다른 이슈가 발생하는데 firstPatientAge의 값을 여러곳에서 출력하게 될 경우가 존재한다면 렌더링을 위해 같은 함수를 여러번 실행하게 된다. 아래 코드는 5번이지만 10000번 반복된다면 함수는 동일한 데이터를 내려주기 위해 10000번 실행된다.

<template>
  <h3>computed vs watch 차이</h3>
  <p>
    {{ firstPatientAge() }}
    {{ firstPatientAge() }}
    {{ firstPatientAge() }}
    {{ firstPatientAge() }}
    {{ firstPatientAge() }}
  </p>
</template>

이러한 이슈를 해결하기 위해 computed 프로퍼티가 등장하였다. computed 프로퍼티는 종속 대상을 caching 하는 특징을 가지고 있어 종속하는 대상이 변경되지 않으면 다시 실행하여 계산하지 않는다. 아래 코드에서 종속 대상은 data이고 console.log를 찍어보며 한번 확인해보자.

콘솔로그

<template>
  <h3>computed vs watch 차이</h3>
  <p v-for="index in 10" :key="index">{{ firstPatientAge() }}</p>
  <p v-for="index in 100" :key="index">{{ computedFirstPatientAge }}</p>
</template>
<script setup lang="ts">
import { computed, ref, reactive } from "vue";

const data = reactive({
  patient: [
    {
      name: "김일",
      age: 20,
      hospitalizationNumber: 2134,
    },
  ],
});

const firstPatientAge = () => {
  console.log("function");
  return data.patient.filter((el) => el.hospitalizationNumber > 2000)[0].age;
};
const computedFirstPatientAge = computed(() => {
  console.log("computed");
  return data.patient.filter((el) => el.hospitalizationNumber > 2000)[0].age;
});

위 사진을 보면 computed 프로퍼티를 사용한 값은 10번 반복되었지만 캐싱 처리가 되어 console.log가 1번만 찍힌 것을 확인할 수 있다. 이러한 장점과 이슈를 해결하기 위해 computed 프로퍼티가 등장하였다.

🐹 computed get, set

Vue computed 속성은 기본적으로 읽기 전용이고 이 속성에 새 값을 할당하려고 하면 에러가 출력된다. 그렇지만 수정이 필요할 경우 getter, setter를 사용하여 속성을 수정 가능하다.

getset

const computedFirstPatientAge = computed({
  get() {
    console.log("computed");
    return data.patient.filter((el) => el.hospitalizationNumber > 2000)[0].age;
  },
  set(newValue) {
    data.patient.filter((el) => el.hospitalizationNumber > 2000)[0].age =
      newValue;
  },
});

computedFirstPatientAge.value = 99;
console.log("data : ", data);

🚧주의점🚧 공식문서에서 모범 사례로 getter에서 사이드 이펙트 사용을 지양하고 있다. 그 이유는 computed 프로퍼트는 다른 값을 가져와서 단순하게 만들어 캐싱 처리하여 사용하는 것을 목적으로 가지고 있다. 그렇지만 계산된 getter 속에서 다른 상태를 변형시키고, 비동기 요청, DOM을 변경하는 행위를 하게 된다면 가독성과 예측 가능성을 안좋게 하기 때문에 다른 방법을 고려해 보는 것이 좋다.

🐹 watch와 차이점

watch는 말 그대로 감시자라고 생각하면 된다. React로 Hook과 비교하자면 useEffect와 비슷하다. watch 프로퍼티는 computed 프로퍼티와 비슷한 방식으로 작동하지만 computed는 상태를 변경하고 싶고 반환해야 할 때 사용하는 것이고 watch 프로퍼티는 오직 상태 반환만이 아닌 다른 부수효과를 처리해야할 때 사용한다. 예로 밑과 같은 상황이 있다.

  • 데이터 페칭
  • DOM 조작
  • 로컬 저장소 / 오디오 재생과 같은 API
  • toast 및 다른 부수 효과

간단하게 말해 이런 부수효과가 아니라면 computed로 사용하는 것이 좋다.

Watch의 남용

Vue는 Vue 인스턴스의 데이터 변경을 관찰하고 이에 반응하는 보다 일반적인 watch 속성을 제공합니다. 다른 데이터 기반으로 변경할 필요가 있는 데이터가 있는 경우, 특히 AngularJS를 사용하던 경우 watch를 남용하는 경우가 있습니다. 하지만 명령적인 watch 콜백보다 computed 속성을 사용하는 것이 더 좋습니다.

공식문서 적혀 있는 말이다.

🐹 결론

  • 대부분의 경우 computed 속성을 사용하는게 좋지만 데이터 Fetching, Dom 조작, toast 및 다른 부수 효과를 처리할 때는 watch를 사용하는 것이 좋다. computed는 최종 응답을 얻을 때 까지 중간 상태를 처리하지 못하지만 watch에 경우에는 중간 상태 처리가 가능하기 때문에 이런 상황일 때도 watch 프로퍼티를 사용하자.

🐹 Reference

profile
안녕하세요. 소프트웨어 엔지니어 제리입니다 🐹

0개의 댓글