watch와 watchEffect에 대한 고찰

MochaChoco·2023년 9월 4일
0
post-thumbnail

vue 3 프로젝트에서 현재 route 경로가 변할 때마다 다른 얼럿을 띄우는 기능을 개발 중이었는데, 웹 사이트 내부 경로가 바뀔때는 얼럿이 잘 떴지만 처음 진입 시에만 얼럿이 뜨지 않는 이슈를 발견했다.

// main page
<script setup lang="ts">
const route = useRoute();

// 페이지 진입시 동작하지 않음
watch([route], (oldValue, newValue) => {
	window.alert(`현재 위치는 ${route.path}입니다.`);
})
</script>

watch 함수 자체가 웹 사이트 처음 진입시 동작하지 않는 것이 원인이었는데, watch 함수를 watchEffect 함수로 변경하니 그제서야 얼럿이 정상적으로 출력됐다. 이번 포스트에서는 watch 함수와 watchEffect 함수 간 어떠한 차이점이 있는지 정리하고자 한다.

watch와 watchEffect란?

watch 함수와 watchEffect 함수는 기존 Vue 2에서 지원하던 Option API의 watch와 유사한 컨셉을 가지고 있다. 이들은 Vue3에서 Composition API가 공식적으로 도입되면서 Reactive한 value를 감지하기 위해 도입되었다.

※ Reactive value란?
참조가 가능한 일종의 변수(ref, reactive, computed 등)로써, 어떤 변수를 Reactive value로 선언하고 값을 변경시키면 Vue는 자동으로 변경사항을 감지하고, 해당 변수를 참조하는 DOM과 Reactive value를 업데이트 한다.

1. watch

// main page
<script setup lang="ts">
const route = useRoute();

// 페이지 진입시 동작하지 않음
watch([route], (oldValue, newValue) => {
	window.alert(`현재 위치는 ${route.path}입니다.`);
})
</script>

watch는 두 개의 필수 인자와 한 개의 선택 인자를 받는다. 첫 번째 인자로 감시할 source, 두 번째 인자로 소스가 변경될때 호출될 callback 함수이다.

※ source에 들어갈 수 있는 요소들
1) 구독할 값을 리턴하는 getter 함수 (예시 : ()=> ref.value)
2) ref, reactive와 같은 반응형 값
3) 1번과 2번 등을 포함한 배열

여러 반응형 값들 중 특정 몇몇 값만 명시적으로 체크하거나, 변화 이전의 값도 확인이 필요하다면 watch를 사용하는 것이 좋다. watch는 lazy한 특성 때문에 명시적으로 입력한 값이 변했을때만 체크되고, 또한 mount된 이후에 변화한 값만 체크한다는 특징도 가지고 있다. 초반에 언급했던 이슈도 페이지가 mount되기 route값이 먼저 변했기 때문에 생긴 이슈였다. 만약 watch가 mount 여부와 관계없이 특정 값을 체크하기 원한다면 watchEffect를 사용하거나 아래에 서술한 세 번째 인자를 사용해야 한다.

※ 세 번째 인자에 들어갈 수 있는 요소들
1) immediate: watch가 생성되는 즉시 callback를 호출한다.
2) deep: source가 object인 경우, deep한 변경 사항에서도 callback을 호출한다.
3) flush: callback의 발생(flush) 타이밍을 조정할 때 사용되며 pre, post, sync 3가지 옵션이 존재한다. 각각 컴포넌트 업데이트 전, 업데이트 후, 동일한 틱 내에서 콜백 호출 여부를 지정한다.
4) onTrack / onTrigger: watch를 디버깅하는 callback 함수를 지정한다.

// main page
<script setup lang="ts">
const route = useRoute();
  
// watch가 생성되는 즉시 동작
watch([route], (oldValue, newValue) => {
	window.alert(`현재 위치는 ${route.path}입니다.`);
}, { immediate: true })	
</script>

watchEffect함수가 아니라 watch 함수로 이번 이슈를 해결하기 위해선 세 번째 인자로 immediate값을 true로 넣어주면 된다.

watch 특징 정리

앞서 말한 watch의 특징을 정리하면 다음과 같다.

1) 필수 인자를 두 개, 선택 인자를 한 개 받는다.
2) 처음에 컴포넌트가 mount될때 실행되지 않는다.
3) 첫 번째 인자에 명시적으로 입력한 값들만 체크한다. 콜백 내에서 사용되는 다른 반응형 값들은 체크하지 않는다.

2. watchEffect

// main page
<script setup lang="ts">
const route = useRoute();
  
// 생성되는 즉시 동작
watchEffect(() => {
	window.alert(`현재 위치는 ${route.path}입니다.`);
})	
</script>

watchEffect는 watch와 달리 한 개의 필수인자와 한 개의 선택인자를 받는다. 첫 번째 인자로 callback 함수를 받는데 선언되는 즉시 함수 내의 반응형 값들을 추적하며, watchEffect 바깥의 요인으로 해당 값들이 변경될 때마다 callback 함수를 다시 실행하게 된다. 하지만 mount 되지 않은 Dom에 접근할 때 에러가 날 수 있으니 주의해야 한다.
두 번째 인자는 선택 값으로 watch와 마찬가지로 에 들어갈 수 있는 요소들은 다음과 같다.

※ 두 번째 인자에 들어갈 수 있는 요소들
1) flush: watch의 flush와 동일
2) onTrack / onTrigger: watch의 onTrack, onTrigger와 동일

watchEffect 특징 정리

watchEffect의 특징을 정리하면 다음과 같다.
1) 필수 인자와 선택 인자를 각각 한 개씩 받는다.
2) 처음에 컴포넌트가 mount될때도 실행된다.
3) 콜백 함수에서 사용되는 반응형 값들을 모두 추적한다. 따라서 watch보다는 덜 명시적이다.

3. 결론

사실 일반적인 경우에서 watch나 watchEffect 어느걸 사용하든 큰 차이는 없다. 하지만 그 둘의 차이점과 사용 용도를 분명히해서 나쁠 것은 없다고 생각한다.

Watch를 사용하면 좋은 경우

1) 명시적으로 추적할 값을 선언하여 필요한 상황에서만 값을 추적하길 원하는 경우
2) 추적한 값의 old value를 보고 싶은 경우

WatchEffect를 사용하면 좋은 경우

1) 명시적으로 특정 값만 추적하기 어려운 경우
2) 컴포넌트가 mount될때 바로 사용하고 싶은 경우

참고 자료

Vue’s watch vs watchEffect, which should I use?
Vue3 Composition API: WatchEffect Vs. Watch
vue.js 공식 문서
watch VS watchEffect in Vue 3 - Must Know Differences

profile
길고 가늘게

0개의 댓글