概述
在日常的開發(fā)中,很多時候我們需要去對一些狀態(tài)進(jìn)行監(jiān)聽,比如當(dāng)顯示學(xué)生的成績列表時,我們使用一個學(xué)生的學(xué)號student_num作為請求成績的參數(shù),如果沒有監(jiān)聽機制,當(dāng)學(xué)號student_num改變時,我們需要依賴用戶的操作去刷新成績。但是有了偵聽器,我們可以通過偵聽器去監(jiān)聽student_num,當(dāng)其發(fā)生改變時,自動去執(zhí)行成績刷新的操作。省去了很多冗余的邏輯。在Vue中,偵聽器主要有兩個,watch和watchEffect。下文將主要介紹他們的用法和區(qū)別。
實例解析
1.watch偵聽器的用法
基本使用
我們可以使用 watch 函數(shù)在每次響應(yīng)式狀態(tài)發(fā)生變化時觸發(fā)回調(diào)函數(shù),下面的代碼中,我們監(jiān)聽一個name屬性的值,使用一個輸入框輸入name的不同值,當(dāng)name的值改變時觸發(fā)回調(diào),代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>watch偵聽器的使用</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="root"></div>
</body>
<script>
const app = Vue.createApp({
setup(props,context){
const {ref,watch} = Vue;
const name = ref('walt');
// 具備懶加載
// 參數(shù)可以拿到原始值和當(dāng)前值
// 用一個偵聽器可以監(jiān)聽多個數(shù)據(jù)
watch(name,(currentValue,prevValue)=>{
console.log(currentValue,prevValue);
})
return {name}
},
template:
`
<div>
<div>Name:<input v-model="name"></div>
</div>
`
});
const vm = app.mount('#root');
</script>
運行結(jié)果:
從上面的代碼中我們可以看到,傳入的第一個參數(shù)name使用了ref包裝,使其具有了響應(yīng)式的屬性,其實,watch 的第一個參數(shù)可以是不同形式的“數(shù)據(jù)源”:它不僅可以是一個 ref (包括計算屬性)、還可以是一個響應(yīng)式對象、一個 getter 函數(shù)、或多個數(shù)據(jù)源組成的數(shù)組,如下所示:
const x = ref(0)
const y = ref(0)
// 單個 ref
watch(x, (newX) => {
console.log(`x is ${newX}`)
})
// getter 函數(shù)
watch(
() => x.value + y.value,
(sum) => {
console.log(`sum of x + y is: ${sum}`)
}
)
// 多個來源組成的數(shù)組
watch([x, () => y.value], ([newX, newY]) => {
console.log(`x is ${newX} and y is ${newY}`)
})
注意:我們不能直接監(jiān)聽對象的屬性,比如下列的做法是不對的
// 不正確的寫法
setup(props,context){
const {watch,reactive,toRefs} = Vue;
const nameObj = reactive({name:'walt'});
watch(nameObj.name,(currentValue,prevValue)=>{
console.log(currentValue,prevValue);
})
const {name} = toRefs(nameObj)
return {name}
}
如上面的代碼所示,直接監(jiān)聽對象的屬性是不行的,需要提供一個返回該屬性的getter函數(shù),正確的寫法如下所示:
// 正確寫法
setup(props,context){
const {watch,reactive,toRefs} = Vue;
const nameObj = reactive({name:'walt'});
watch(()=>nameObj.name,(currentValue,prevValue)=>{
console.log(currentValue,prevValue);
})
const {name} = toRefs(nameObj)
return {name}
}
深層偵聽器
這里引用官網(wǎng)的例子解釋, 直接給 watch() 傳入一個響應(yīng)式對象,會隱式地創(chuàng)建一個深層偵聽器——該回調(diào)函數(shù)在所有嵌套的變更時都會被觸發(fā):
const obj = reactive({ count: 0 })
watch(obj, (newValue, oldValue) => {
// 在嵌套的屬性變更時觸發(fā)
// 注意:`newValue` 此處和 `oldValue` 是相等的
// 因為它們是同一個對象!
})
obj.count++
相比之下,一個返回響應(yīng)式對象的 getter 函數(shù),只有在返回不同的對象時,才會觸發(fā)回調(diào):
watch(
() => state.someObject,
() => {
// 僅當(dāng) state.someObject 被替換時觸發(fā)
}
)
我們可以添加deep :true
,來將上面的例子轉(zhuǎn)換成深層偵聽器,代碼如下:
watch(
() => state.someObject,
(newValue, oldValue) => {
// 注意:`newValue` 此處和 `oldValue` 是相等的
// *除非* state.someObject 被整個替換了
},
{ deep: true }
)
需要注意的是,深層偵聽器會遍歷被偵聽對象的嵌套屬性,為了性能考慮,謹(jǐn)慎使用
即時回調(diào)監(jiān)聽器
watch 默認(rèn)是懶執(zhí)行的:僅當(dāng)數(shù)據(jù)源變化時,才會執(zhí)行回調(diào)。但在某些場景中,我們希望在創(chuàng)建偵聽器時,立即執(zhí)行一遍回調(diào)。比如,我們想請求一些初始數(shù)據(jù),然后在相關(guān)狀態(tài)更改時重新請求數(shù)據(jù)。
我們可以通過傳入 immediate: true 選項來強制偵聽器的回調(diào)立即執(zhí)行,代碼如下:
watch(source, (newValue, oldValue) => {
// 立即執(zhí)行,且當(dāng) `source` 改變時再次執(zhí)行
}, { immediate: true })
2、watchEffect偵聽器的用法·
watchEffect幀聽器是立即執(zhí)行的,它不像watch是懶加載的,而且它不需要傳遞要偵聽的內(nèi)容,會自動感知代碼依賴,不需要傳遞很多參數(shù),只需要傳遞一個回調(diào)函數(shù)就可以。引用Vue官網(wǎng)的例子,比如:當(dāng) todoId 的引用發(fā)生變化時使用偵聽器來加載一個遠(yuǎn)程資源:
const todoId = ref(1)
const data = ref(null)
watch(todoId, async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
}, { immediate: true })
上面的todoId一次是作為源,另一次是在回調(diào)中使用的,可以用 watchEffect 函數(shù) 來簡化上面的代碼。watchEffect() 允許我們自動跟蹤回調(diào)的響應(yīng)式依賴。上面的偵聽器可以重寫為:
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
使用watchEffect,回調(diào)會立即執(zhí)行,不需要指定 immediate: true。在執(zhí)行期間,它會自動追蹤 todoId.value 作為依賴(和計算屬性類似)。每當(dāng) todoId.value 變化時,回調(diào)會再次執(zhí)行。有了 watchEffect(),不再需要明確傳遞 todoId 作為源值
3 停止偵聽器
停止偵聽器
?
在 setup() 或 <script setup>
中用同步語句創(chuàng)建的偵聽器,會自動綁定到宿主組件實例上,并且會在宿主組件卸載時自動停止。因此,在大多數(shù)情況下,不需要關(guān)心怎么停止一個偵聽器。偵聽器必須用同步語句創(chuàng)建:如果用異步回調(diào)創(chuàng)建一個偵聽器,那么它不會綁定到當(dāng)前組件上,必須手動停止,以防內(nèi)存泄漏。如下方這個例子:
<script setup>
import { watchEffect } from 'vue'
// 它會自動停止
watchEffect(() => {})
// ...這個則不會!
setTimeout(() => {
watchEffect(() => {})
}, 100)
</script>
要手動停止一個偵聽器,請調(diào)用 watch 或 watchEffect 返回的函數(shù):文章來源:http://www.zghlxwxcb.cn/news/detail-473737.html
const stop= watchEffect(() => {})
// ...當(dāng)該偵聽器不再需要時
stop()
總結(jié)
至此,本文已經(jīng)介紹完了watch和watchEffect幀聽器的使用和注意點,最后總結(jié)下兩個偵聽器的區(qū)別,watch具備懶加載,參數(shù)可以拿到原始值和當(dāng)前值,用一個偵聽器可以監(jiān)聽多個數(shù)據(jù);而watchEffect偵聽器是立即執(zhí)行的,不需要傳遞要偵聽的內(nèi)容,它會自動感知代碼依賴,但是watchEffect無法獲取改變之前的值文章來源地址http://www.zghlxwxcb.cn/news/detail-473737.html
到了這里,關(guān)于Vue Composition API之偵聽器watch/watchEffect的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!