Vue3의 watch / watchEffect
watch
vs watchEffect
– Vue 3 Composition API에서의 반응형
Vue 3 Composition API에서는 반응형 데이터의 변화를 감시하기 위해
watch
와 watchEffect
두 가지 기능을 제공합니다.두 도구는 유사해 보이지만, 동작 방식, 실행 시점, 사용 목적에서 뚜렷한 차이가 있습니다.
공통점
항목 | watch | watchEffect |
Vue 3에서만 사용 가능 | ❌ (Vue 2에서도 Options API 기반 사용 가능) | ✅ Composition API 전용 |
Composition API에서 사용 | ✅ | ✅ |
반응형 데이터 감시 | ✅ | ✅ |
내부에서 side effect 처리 | ✅ | ✅ |
차이점
항목 | watch | watchEffect |
감시 대상 | 명시적 (ref, getter, 배열 등) | 암시적 (함수 내부의 종속성 추적) |
실행 시점 | lazy (기본), immediate 옵션 가능 | 즉시 실행 (기본) |
이전 값 접근 | ✅ 가능 | ❌ 불가능 |
Side Effect 제어 | 명확히 가능 (debounce 등) | 간단한 반응 처리에 유리 |
종속성 자동 추적 | ❌ 수동 지정 필요 | ✅ 자동 추적 |
취소 로직 (invalidate) | ✅ 가능 | ✅ 가능 |
watch – 명시적 감시와 비교가 필요한 경우 사용
주요 특징
- 감시 대상(ref, reactive 속성, getter 등)을 명시적으로 지정
- 변경 전후 값(newVal, oldVal) 을 확인 가능
- 비동기 작업, debounce/throttle 처리에 적합
사용 예제 1: 기본 구조
import { ref, watch } from 'vue' const count = ref(0) watch(count, (newVal, oldVal) => { console.log(`count changed from ${oldVal} to ${newVal}`) })
사용 예제 2: getter 사용
watch( () => user.value.name, (newName, oldName) => { console.log(`user name changed from ${oldName} to ${newName}`) } )
사용 예제 3: 여러 개 감시
watch( [() => a.value, () => b.value], ([newA, newB], [oldA, oldB]) => { console.log('a or b changed') } )
옵션 사용
watch(count, callback, { immediate: true, // mount 시에도 실행 deep: true, // 객체/배열의 내부 변경 감지 })
watchEffect – 선언형 방식의 반응 처리
주요 특징
- 감시 대상을 명시하지 않음
- 함수 내부에서 사용한 모든 ref/ reactive가 자동 추적 대상이 됨
- 즉시 실행됨
oldValue
를 알 필요 없고, 단순한 반응형 사이드 이펙트를 다룰 때 적합
기본 예제
import { watchEffect, ref } from 'vue' const count = ref(0) watchEffect(() => { console.log(`The current count is ${count.value}`) })
count.value가 바뀔 때마다 자동으로 실행
여러 종속성 추적
watchEffect(() => { console.log(`User: ${user.value.name}, Profile: ${profile.value.job}`) })
user 또는 profile 내부 속성 중 하나라도 바뀌면 실행됨
실전 사용 기준 – 언제 어떤 걸 써야 하나?
상황 | 사용 추천 |
데이터 변경 전후 비교가 필요한 경우 | watch |
감시 대상이 복잡하고 명시적으로 지정해야 하는 경우 | watch |
즉시 실행 + 여러 반응형 데이터 추적 + oldValue 불필요 | watchEffect |
간단한 반응형 연산 또는 side effect (ex. 콘솔 출력, fetch) | watchEffect |
비동기 처리에 대한 취소 로직이 필요한 경우 | watch (with onInvalidate ) |
⚠️ 주의: watchEffect는 모든 변경에 민감하다
watchEffect(() => { console.log(`Hello ${user.value.name}`) })
위 코드는
user
객체가 다시 할당되거나 내부 속성이 바뀌면 무조건 실행됨.너무 많은 데이터를 감지하거나 무거운 로직을 넣으면 불필요한 리렌더링이 발생할 수 있음.
복잡한 연산이나 비동기 처리에는 watch가 더 적절합니다.
Bonus: 비동기 작업 처리 시 onInvalidate
watch(query, async (newQuery, _, onInvalidate) => { let cancelled = false onInvalidate(() => { cancelled = true }) const result = await fetchData(newQuery) if (!cancelled) { data.value = result } })
이전 요청이 완료되기 전에 새로운 요청이 들어올 경우 이전 작업을 취소할 수 있음
정리
항목 | watch | watchEffect |
Vue 버전 | Vue 2/3 | Vue 3 Composition API 전용 |
감시 대상 지정 | ✅ 명시 필요 | ❌ 자동 추적 |
실행 시점 | lazy (기본), immediate 가능 | ✅ 즉시 실행 |
이전 값 접근 | ✅ 가능 | ❌ 불가능 |
종속성 추적 방식 | 수동 | 자동 |
비동기 제어 | ✅ onInvalidate() 가능 | ✅ 가능하나 보통 사용하지 않음 |
적합한 상황 | 비교, 비동기, 특정 감시 대상 | 선언적 로직, 단순 반응 처리 |