# watch와 watchEffect의 차이

Vue.js 3은 watch 외에 watchEffect 가 추가되었습니다. 두 키워드 모두 반응성을 가진 데이터 변경을 감지하는데 사용합니다. 큰 차이점은 다음과 같습니다.

  • watch는 이전값, 현재값 모두 필요한 경우 사용합니다.
  • watchEffect는 현재값만 필요할 때 사용합니다.
  • watchEffect는 감시하는 대상을 명시적으로 지정하지 않습니다.
  • watchEffect는 watchEffect에 전달하는 콜백 메소드 안에 반응성을 가진 데이터를 사용하는 경우에만 호출됩니다.

테스트를 위한 예제입니다. watch 1개와 watchEffect 3개를 만들었습니다.

<template>
  <div>{{ count }}</div>
  <div>{{ count2 }}</div>
  <button @click="count = Math.random()">change</button>
  <button @click="count2 = Math.random()">change</button>
</template>

<script>
import { ref, watch, watchEffect } from 'vue'
export default {
  setup() {
    const count = ref(0)
    const count2 = ref(1)
    // count가 변화될 때 이전/현재 값을 사용할 수 있습니다.
    watch(count, (current, previous) => { console.log('[count] watch => ', current, previous) })
    // count 또는 count2가 변경되는 경우 호출됩니다.
    watchEffect(() => { console.log('[count, count2] watchEffect', count.value, count2.value) })
    // count가 변경될 때 호출됩니다.
    watchEffect(() => { console.log('[count] watchEffect', count.value) })
    // count2가 변경될 때 호출됩니다.
    watchEffect(() => { console.log('[count2] watchEffect', count2.value) })
    return { count, count2 }
  }
}
</script>

각 시점별 출력된 로그입니다.

컴포넌트가 등록될 때

[count, count2] watchEffect 0 1
[count] watchEffect 0
[count2] watchEffect 1

count가 변경될 때

[count] watch =>  0.16419505711416238 0
[count, count2] watchEffect 0.16419505711416238 1
[count] watchEffect 0.16419505711416238

count2가 변경될 때

[count, count2] watchEffect 0 0.7238270105035622
[count2] watchEffect 0.7238270105035622

# 사이드이펙트

watchEffect 는 반응성을 가진 데이터가 만들어질 때에도 호출됩니다. 이름에 "effect" 가 붙은 것 처럼 반응성 데이터가 만들어질때의 "사이드이펙트" 도 감지합니다. Vue.js 3은 refreactive 가 만들어내는 ReactiveEffect 라는 사이드이펙트를 만들어냅니다. 이 사이드이펙트는 effectStack 에서 관리됩니다.

refreactive 는 값이 변화되는 마지막 시점에 trigger (opens new window) 를 호출합니다. 이것으로 반응성 데이터 조작의 "사이드이펙트" 를 발생시킵니다. 발생한 "사이드이펙트" 는 doWatch (opens new window) 에서 처리됩니다.

watchEffectwatch 구현의 최소화 버전입니다. watch 는 반응성을 가지는 데이터의 이전, 이후값에 대한 타입 체크 및 상태를 확인 한 다음 처리하는 반면 watchEffect 는 사이드이펙트 발생 여부만 사용합니다.

추가로 ReactiveEffect 는 아래와 같은 추가 옵션과 핸들러를 가지고 있습니다. 이 장에서 자세히 다루지 않습니다.

export interface ReactiveEffectOptions {
  lazy?: boolean
  scheduler?: (job: ReactiveEffect) => void
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
  onStop?: () => void
  allowRecurse?: boolean
}