[ Reference ]
https://vuejs.org/guide/essentials/watchers.html
Watchers | Vue.js
vuejs.org
1. Basic Example
Vue 에서는 ** computed ** 를 이용해서 값을 선언적으로 계산할 수 있다. 하지만 상태 변화에 따라 발생하는 사이드 이펙트를 다뤄야하는 상황이 발생하기도 한다. 예를 들어서 DOM 을 조작한다고 할 때, 혹은 비동기 연산의 결과에 따라 다른 상태를 변경해야하는 것 등이 있다. 이런 경우 Composition API 의 watch 함수를 사용하면 반응성 있는 상태가 변경될 때마다 콜백 함수를 실행할 수 있다.
<script setup>
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Questions usually contain a question mark. ;-)')
// watch works directly on a ref
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.indexOf('?') > -1) {
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
answer.value = (await res.json()).answer
} catch (error) {
answer.value = 'Error! Could not reach the API. ' + error
}
}
})
</script>
<template>
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</template>
(* 위의 예제 코드를 잠깐 해석해보자면 question 이라고 하는 Ref 로 인해 반응성 있는 상태를 watch 함수를 이용해서 감시하고 있는 중이다. input 창으로 question 값이 바뀔 때 비동기 만약 '?' 가 question 내에 존재할 경우, 처음에 answer 값은 'Thinking...' 으로 바뀐다. 그리고 try - catch 문으로 넘어가서 비동기 작업을 진행한다. fetch 에 있는 경로로 api 요청을 하고 만약 이 요청이 정상적으로 수행된다면 answer 의 값은 응답 받은 파일의 answer 속성 값으로 변경하게 되고 네트워크 에러가 날 경우에는 catch 문에 있는 내용으로 answer 값이 바뀔 것이다. 이 예시는 하나의 상태 변화로 인해 다른 상태를 비동기 연산하여 변경하는 케이스가 된다. )
Watch Source Types
watch 의 첫 번째 인자는 ** computed ** 를 포함해서 반응성 있는 상태, 반응성 있는 객체, getter 함수, 혹은 여러 다양한 요소를 갖고 있는 배열일 수 있다.
const x = ref(0)
const y = ref(0)
// single ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// array of multiple sources
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
반응성 있는 객체를 다룰 때는 다음과 같이 사용할 수 없다.
const obj = reactive({ count: 0 })
// this won't work because we are passing a number to watch()
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
대신에 getter 함수를 이용하면 원하는 결과를 가져올 수 있다.
// instead, use a getter:
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
(* Vue 를 자주 사용해 본 사람이라면 저렇게 getter 함수를 이용해서 요소를 가져오는 경우가 많이 있다는 것을 알 수 있다. 예를 들어 props 의 default 로 지정해줄 때나, Vuex 를 사용할 때 state 의 값을 할당하는 등에서 저렇게 하는 경우가 종종 있었을 것이다.)
물론, watch 를 이용해서 반응성 있는 객체의 요소가 아닌 객체 그 자체를 가져올 수는 있다. 그 경우에는 Deep Watchers 가 발동한다. Deep 에서 알 수 있듯이 중첩된 객체에서도 변화가 감지되면 watch 가 실행된다.
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// fires on nested property mutations
// Note: `newValue` will be equal to `oldValue` here
// because they both point to the same object!
})
obj.count++
바로 위의 예시와 바로 아래의 예시는 getter 함수를 사용했느냐 안 했느냐의 차이다. getter 함수의 경우 다른 객체를 반환하는 용도로 사용되는 것이며 만약에 이 반환된 새로운 객체에도 Deep watcher 를 적용하고 싶다면 옵션을 추가로 적용해야 한다.
watch(
() => state.someObject,
(newValue, oldValue) => {
// Note: `newValue` will be equal to `oldValue` here
// *unless* state.someObject has been replaced
},
{ deep: true }
)
Deep Watch 는 아무래도 중첩된 것까지 모두 감시하기 때문에 큰 데이터 구조에서 사용할 경우 비용이 많이 들 수 있다. 꼭 필요할 때만 사용하도록 해야 하고 성능에 미칠 수 있는 영향들은 주의해서 사용해야 한다.
2. watchEffect( )
** watch ** 는 감지하기로 한 인자가 변경되기 전까지는 콜백을 호출되지 않는다. 그러나 비동기로 초기 데이터를 가져오고 나서 그와 관련된 상태가 변경될 때마다 데이터를 다시 가져와야 하는 경우. 이런 경우에는 watchEffect( ) 를 이용해서 단순화할 수 있다. 이 hook 을 사용하면 반응 의존성을 알아서 자동으로 추적하고 발생할 수 있는 side effect 를 즉각적으로 수행해낼 수 있다.
const url = ref('https://...')
const data = ref(null)
async function fetchData() {
const response = await fetch(url.value)
data.value = await response.json()
}
// fetch immediately
fetchData()
// ...then watch for url change
watch(url, fetchData)
watchEffect(async () => {
const response = await fetch(url.value)
data.value = await response.json()
})
아래의 watchEffect 는 콜백 함수가 바로 실행된다. 그리고 실행될 때 자동으로 반응 의존성으로 url.value 를 추적하고 이 값이 변경될 때마다 콜백이 다시 실행된다.
** watch ** 는 명시적으로 감시된 인자만을 추적한다. 콜백 내부에서 접근된 것 내용들은 추적할 수 없다. 또, 콜백 함수는 인자가 실제로 변경된 후에만 실행된다. watcher 의존성 추적과 side effect 를 분리해서 콜백이 실행돼야 할 시기를 보다 정확하게 제어할 수 있다.
** watchEffect ** 는 의존성 추적과 부작용을 한 번에 해결한다. 동기적으로 실행될 때 접근하는 모든 반응성 있는 상태들을 추적한다. 덕분에 더 편리하고 일반적으로 테서 코드가 생성되지만 반응 의존성이 덜 명확해진다는 단점이 있다
'(준)공식 문서 > Vue.js' 카테고리의 다른 글
[ Vue.js 3 공식 문서 ] 2. Essentials - Components Basics (Component, Props, Emits ) (0) | 2022.02.28 |
---|---|
[ Vue.js 3 공식 문서 ] 2. Essentials - Template Refs (0) | 2022.02.23 |
[ Vue.js 3 공식 문서 ] 2. Essentials - Lifecycle Hooks (0) | 2022.02.22 |
[ Vue.js 3 공식 문서 ] 2. Essentials - Form Input Binding (v-model) (0) | 2022.02.22 |
[ Vue.js 3 공식 문서 ] 2. Essentials - Event Handling (v-on) (0) | 2022.02.22 |