watch 和 watchEffect
計算屬性是通過聲明性的計算衍生值,然而有些情況,我們需要在狀態(tài)變化時執(zhí)行一些"副作用",例如更改DOM,或是根據(jù)異步操作的結果去修改另一處的狀態(tài)。
一般來說,computed主要是涉及計算某些值的時候使用,
watch(Effect)函數(shù)主要是監(jiān)聽某個狀態(tài),當某個狀態(tài)改變時才會觸發(fā)回調函數(shù)
watch參數(shù)(監(jiān)聽源,回調函數(shù),{immediate: '" ", deep: " "}
第一個參數(shù)可以是不同形式的“數(shù)據(jù)源”:
它可以是一個 ref (包括計算屬性),不能是響應式對象的屬性值,解決方法就是用一個對象的屬性值的函數(shù)
一個響應式對象
一個 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}`)
})
const obj = reactive({ count: 0 })
// 錯誤,因為 watch() 得到的參數(shù)是一個 number
watch(obj.count, (count) => {
console.log(`count is: ${count}`)
})
上述問題的解決方案:用一個返回該屬性的 getter 函數(shù):
// 提供一個 getter 函數(shù)
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`)
}
)
watchEffect
立即執(zhí)行傳入的回調函數(shù),同時響應式的追蹤依賴,依賴改變就會重新運行函數(shù)
watchEffect(async () => {
const response = await fetch(
`https://jsonplaceholder.typicode.com/todos/${todoId.value}`
)
data.value = await response.json()
})
這個例子不用想watch一樣手動指定immediate:true
,他會在組件首次渲染的時候就會執(zhí)行一次,并且自動追蹤todoId.value
作為依賴,當todoId.value
發(fā)生改變時,回調就會再次執(zhí)行。相對于watch,不用指定immediate配置項,且不用明確指定數(shù)據(jù)源todoId.value
對于只有一個依賴的例子來說,watchEffect
的好處相對較小,但是對于有多個依賴項的偵聽器來說,使用watchEffect
可以手動消除維護依賴列表的負擔。此外,如果你需要偵聽一個嵌套數(shù)據(jù)結構的幾個屬性,watchEffect
可能比watch
更有效,因為它將只跟蹤回調函數(shù)中使用到的屬性,而不是遞歸的跟蹤所有屬性。
Tips:
watchEffect
僅僅會在同步執(zhí)行期間追蹤依賴,當使用異步回調的時候,只有在第一個await正常工作前訪問的屬性才會被跟蹤
watch
vs. watchEffect
watch
和 watchEffect
都能響應式地執(zhí)行有副作用的回調。它們之間的主要區(qū)別是追蹤響應式依賴的方式:
-
watch
只追蹤明確偵聽的數(shù)據(jù)源。它不會追蹤任何在回調中訪問到的東西。另外,僅在數(shù)據(jù)源確實改變時才會觸發(fā)回調。watch
會避免在發(fā)生副作用時追蹤依賴,因此,我們能更加精確地控制回調函數(shù)的觸發(fā)時機。 -
watchEffect
,則會在副作用發(fā)生期間追蹤依賴。它會在同步執(zhí)行過程中,自動追蹤所有能訪問到的響應式屬性。這更方便,而且代碼往往更簡潔,但有時其響應性依賴關系會不那么明確
函數(shù)觸發(fā)時機
watchEffect 是一個副作用函數(shù), 在 DOM 掛載或更新之前就會觸發(fā)。
<template>
<div>
動物:
<input id="ipt" v-model="fish.name" />
</div>
</template>
<script lang="ts" setup>
import { reactive, watchEffect } from 'vue'
interface Animal {
name: string
type: string
}
let fish = reactive<Animal>({
name: '酸菜魚',
type: '又酸又菜又多余',
})
watchEffect<Animal>(() => {
console.log('fish', fish.name)
const ipt: HTMLElement = document.querySelector('#ipt') as HTMLElement
console.log('ipt', ipt)
})
</script>
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iMUTAjBX-1680081569864)(C:\Users\26387\AppData\Roaming\Typora\typora-user-images\image-20230329164828475.png)]
第一次獲取到的元素是 null,執(zhí)行第二次監(jiān)聽的時候才會獲取到元素。
清除watchEffect的副作用的方法
通過flush:post 可以避免副作用,在 DOM 更新后運行副作用,確保模板引用與 DOM 保持同步,并引入正確元素。
或者使用watchPostEffect()
,該函數(shù)和watctEffect()
一樣,不同之處在于會直接在Vue 更新后執(zhí)行
import { watchPostEffect } from 'vue'
watchPostEffect(() => {
/* 在 Vue 更新后執(zhí)行 */
})
?
? onTrack 和 onTrigger 用于調試一個偵聽器的行為。
? 清除副作用函數(shù)(onInvalidate)。
? watchEffect 的第一個參數(shù)回調函數(shù),也有自己的參數(shù) – onInvalidate。它也是一個函數(shù),用于清除 effect 產(chǎn)生的副作用
watchEffect<Type>(
(oninvalidate) => {
console.log('監(jiān)聽參數(shù)',)
oninvalidate(() => {
console.log('before')
})
}
....其他邏輯代碼
)
? oninvalidate 只作用于異步函數(shù),只有兩種情況才會被調用:
- watchEffect 第一個參數(shù)是 effect 回調函數(shù),當 effect 被重新調用時。
- 當監(jiān)聽器被注銷時。
watch的觸發(fā)時間是:監(jiān)聽某個特定屬性變化時,并能夠返回改變前后的值
停止偵聽器
一個關鍵點是,偵聽器必須用同步語句創(chuàng)建:如果用異步回調創(chuàng)建一個偵聽器,那么它不會綁定到當前組件上,你必須手動停止它,以防內存泄漏。如下方這個例子:文章來源:http://www.zghlxwxcb.cn/news/detail-829050.html
const unwatch = watchEffect(() => {})
// ...當該偵聽器不再需要時
unwatch()
注意,需要異步創(chuàng)建偵聽器的情況很少,請盡可能選擇同步創(chuàng)建。如果需要等待一些異步數(shù)據(jù),你可以使用條件式的偵聽邏輯:文章來源地址http://www.zghlxwxcb.cn/news/detail-829050.html
// 需要異步請求得到的數(shù)據(jù)
const data = ref(null)
watchEffect(() => {
if (data.value) {
// 數(shù)據(jù)加載后執(zhí)行某些操作...
}
})
到了這里,關于Vue3watch 和 watchEffect的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!