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) | ✅ 가능 | ✅ 가능 |
1import { ref, watch } from 'vue'
2
3const count = ref(0)
4
5watch(count, (newVal, oldVal) => {
6 console.log(`count changed from ${oldVal} to ${newVal}`)
7})1watch(
2 () => user.value.name,
3 (newName, oldName) => {
4 console.log(`user name changed from ${oldName} to ${newName}`)
5 }
6)1watch(
2 [() => a.value, () => b.value],
3 ([newA, newB], [oldA, oldB]) => {
4 console.log('a or b changed')
5 }
6)watch(count, callback, {
immediate: true, // mount 시에도 실행
deep: true, // 객체/배열의 내부 변경 감지
})oldValue를 알 필요 없고, 단순한 반응형 사이드 이펙트를 다룰 때 적합1import { watchEffect, ref } from 'vue'
2
3const count = ref(0)
4
5watchEffect(() => {
6 console.log(`The current count is ${count.value}`)
7})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(() => {
console.log(`Hello ${user.value.name}`)
})위 코드는 user 객체가 다시 할당되거나 내부 속성이 바뀌면 무조건 실행됨.
너무 많은 데이터를 감지하거나 무거운 로직을 넣으면 불필요한 리렌더링이 발생할 수 있음.
복잡한 연산이나 비동기 처리에는 watch가 더 적절합니다.
onInvalidate1watch(query, async (newQuery, _, onInvalidate) => {
2 let cancelled = false
3
4 onInvalidate(() => {
5 cancelled = true
6 })
7
8 const result = await fetchData(newQuery)
9 if (!cancelled) {
10 data.value = result
11 }
12})이전 요청이 완료되기 전에 새로운 요청이 들어올 경우 이전 작업을 취소할 수 있음
| 항목 | watch | watchEffect |
|---|---|---|
| Vue 버전 | Vue 2/3 | Vue 3 Composition API 전용 |
| 감시 대상 지정 | ✅ 명시 필요 | ❌ 자동 추적 |
| 실행 시점 | lazy (기본), immediate 가능 | ✅ 즉시 실행 |
| 이전 값 접근 | ✅ 가능 | ❌ 불가능 |
| 종속성 추적 방식 | 수동 | 자동 |
| 비동기 제어 | ✅ onInvalidate() 가능 | ✅ 가능하나 보통 사용하지 않음 |
| 적합한 상황 | 비교, 비동기, 특정 감시 대상 | 선언적 로직, 단순 반응 처리 |