Vue - method computed watch 비교

이하은·2022년 1월 5일
6

Vue

목록 보기
1/1
post-thumbnail

글을 작성하게 된 배경

Vue를 입문하시는 백엔드 동료 개발자분께서 Vue의 method computed watch 함수에 대해 언제 어떻게 써야하는가에 대해 고민이 있으시다고 하셔서, 저도 Vue에 대해 잘 아는건 아니지만 도움이 됐으면 하는 마음으로 정리해 보았습니다. 혹시 잘못된 부분이 있으면 댓글로 남겨주시면 감사하겠습니다. 🙏


컴포넌트 리랜더링

하나의 파일 컴포넌트는 사실 하나의 함수라고 이해하면 된다.
App.vue 라는 파일은 아래처럼 커다란 함수이다.

const App = (){
	컴포넌트 코드 작성
}

이 함수안의 data 값이 변경될때에 값이 알아서 스스로 변경되는걸로 보이지만 사실상 해당 data는 변경된게 아니다.
data가 변경되기전 App 함수가 죽고 data가 달라진 새로운 App 함수가 실행된 것이다.
이것을 컴포넌트 리랜더링이라고 부른다.
하나의 데이터가 바뀔때에 App 전체 함수가 실행되기 때문에 App 함수 안에 있는 모든 코드들이 재 실행된다.


Method

method 속성 함수는 아래처럼 아주 심플하게 그냥 함수를 단순히 정의한 것이다.

const App = (){
	const method속성함수 = () => {};
}

당연하게도 위 method 속성함수는 App 함수가 재호출(= 리랜더링, = 데이터변경) 될 때마다 함수가 다시 등록될 것이다.
성능이 좋지 못하다.
그래서 나온게 computed 함수이다.


Computed

computed 속성 함수는 좀 특이하다. 단순한 함수를 정의한 method 와 달리 뷰에서 자체적으로 제공해주는 구독 기능이 있고 문법상 지켜야 할것도 많다.
computed 속성 함수는 일반적인 함수와 개념이 좀 다르다.

computed 문법의 특이사항 (method와의 차이점)

  1. template에서 호출시 ()를 적지 않아야 된다.
  2. 파라메터를 직접 넣을 수 없다.
  3. getter computed 함수는 return 값이 반드시 존재해야 한다.

vue 공식문서 사용방법

<template>
  <div>
    <p>원본 메시지: "{{ message }}"</p>
    <p>역순으로 표시한 메시지: "{{ reversedMessage }}"</p>
  </div>
</template>

<script>
export default {
  name: 'test',
  data(){
    return {
      message: '안녕하세요'
    }
  },
  computed: {
    reversedMessage: function () {
      return this.message.split('').reverse().join('')
    }
  }
}
</script>

computed 속성 함수는 해당 함수 안에서 사용된 data들을 알아서 구독한다. 구독하고 있는 값이 변경되면 변경된 값을 반영하여 계산하고 출력한다.

이 함수는 함수를 실행한 결과 값을 캐싱하여 저장한다. 구독하는 data가 변경이 없으면 App 컴포넌트가 재호출(= 리랜더링, = 데이터변경) 되어도 함수를 다시 등록하지 않는다.
구독하는 data가 변경될때에만 computed 함수를 재실행 하여 반환하는 값을 업데이트한다.
함수안에서 사용되지 않은, 즉 구독하고 있지 않는 data가 변경될때, App 컴포넌트가 리랜더링되어도 캐싱된 데이터를 사용하기 때문에 함수를 다시 등록하지 않는다. 그래서 성능이 좋다.

computed 함수를 getter 함수와 setter 함수로 사용할 수 있는데 위에서 처럼 getter 함수로 사용하는 경우, 함수를 쓰는 목적은 이 함수가 반환하는 값을 얻기 위해서 사용된다. 따라서 return 값이 반드시 있어야 한다.


Watch

computed와 마찬가지로 특정한 데이터를 구독하고 있다. 구독하고 있는 data가 업데이트 될 때에 등록한 함수가 콜백 함수로서 실행된다.
업데이트된 값이 첫번째 인수로 들어오고 업데이트 전 값이 두번째 인수로 들어온다.
data가 변경될 때 다른 작업을 실행하는 로직 만 있고 return 값이 필요 없을 때 쓰기 좋다.

위에서 사용한 computed 코드를 watch로 변경하면 아래와 같다. computed는 선언형으로 쓰는 반면 watch는 명령형으로 쓴다. 선언형이 더 가독성이 좋고 코드가 짧다.

<template>
  <div>
    <p>원본 메시지: "{{ message }}"</p>
    <p>역순으로 표시한 메시지: "{{ reversedMessage }}"</p>
  </div>
</template>

<script>
export default {
  name: 'test',
  data(){
    return {
      message: '안녕하세요',
      reversedMessage: ''
    }
  },
  watch: {
    message: function (newVal, oldVal) {
      this.reversedMessage = newVal.split('').reverse().join('')
    }
  }
}
</script>

method computed watch 비교

❓ 컴포넌트가 리랜더링 될 때마다 함수가 등록되는가?

method O / computed X / watch O

❓ 특정한 값 data가 변환되는것을 감지 하는가?

method X / computed O / watch O

❓ 함수를 이벤트 함수 자리에 등록할 수 있는가?

method O / computed X / watch X

method만 뷰에서 기능을 제공해주는게 따로 없는 일반적으로 정의된 함수이기 때문에 가능하다. computed watch는 각자의 쓰여야 할 위치와 문법이 따로 있다.

❓ return 값에 관하여

method: 그냥 일반 함수. return 해도 되고 안해도 되고 개발자가 어디에 사용하기 나름이다.
computed: getter computed 함수는 반드시 값을 return 해야한다.
watch: 개발자가 코드상에서 직접 해당 함수를 호출하는게 아니라서 호출된 return 값을 알 수 가 없고 딱히 쓸 일도 없다.


만약 내가 뷰 코드를 쓴다면?

method에는 이벤트 함수만 등록할 것이다. 아래처럼 "return 값" 을 얻기위해 사용하는 위치에는 computed 를 쓸것이다.

<p>원본 메시지: "{{ method속성함수() }}"</p>
<p>원본 메시지: "{{ computed속성함수 }}"</p>

computed는 반환값으로 변수로서의 역할로만 쓸거같다. 그리고 computed 안에서 return 하는 data 외의 다른 data를 직접 변경해서는 안된다. 해당 함수는 반환하는 값에만 의의가 있기 때문.

watch 함수 안에서는 return 값이 없이 어떠한 로직을 실행하고 싶을때 사용할 것이다.

그리고 함수안에서 여러개의 data를 직접 변경할 경우에 사용할 것이다.


React 에도 Vue 의 watch, computed 와 비슷한 문법이 있는가?

이 글을 작성하게 된 계기인 백엔드 개발자분께서 추가적으로 이러한 질문을 해주셨었다.

뷰와 리액트는 다른 프레임워크이기 때문에 아래 개념이 1대1로 같은 개념은 절대 아니다.

하지만 그중에서 비슷한 점을 꼽아보자면 리액트에는 아래 훅의 특성이 비슷한 것 같다.

useEffect - watch

특정한 값을 바라보고 있고 해당 값이 바뀔때 실행할 수 있다.(deps)

"업데이트 시점"에 해당 로직이 실행된다는 것이 중요할 뿐 함수가 반환하는 값이 없다.

useMemo, useCallback - computed

특정한 값을 바라보고 있고 해당 값이 바뀔때 실행할 수 있다.(deps)

반환하는 값이 있는 getter 함수이다. 구독하고 있는 데이터가 변경되기 전까진 반환 값을 캐싱하고 있다가 데이터가 변경될 때에만 함수를 실행해서 반환값을 업데이트 한다.


참고 문서

profile
완벽함보단 꾸준함으로

0개의 댓글