一文詳解vue3?watchEffect監(jiān)聽的各種姿勢用法
watchEffect 監(jiān)聽不同數(shù)據(jù)源
watchEffect 會自動追蹤在其回調(diào)函數(shù)中使用的所有響應(yīng)式依賴,無需顯式指定數(shù)據(jù)源。
1. 監(jiān)聽單個 ref
import { ref, watchEffect } from 'vue'
const count = ref(0)
// 自動追蹤 count
watchEffect(() => {
console.log('count 值:', count.value)
// 當(dāng) count 變化時自動執(zhí)行
})
// 修改值會觸發(fā)
count.value++ // 輸出: count 值: 1
2. 監(jiān)聽多個 ref
import { ref, watchEffect } from 'vue'
const count = ref(0)
const name = ref('John')
const age = ref(18)
// 自動追蹤所有使用的 ref
watchEffect(() => {
console.log(`姓名: ${name.value}, 年齡: ${age.value}, 計數(shù): ${count.value}`)
// 當(dāng) name、age 或 count 任何一個變化時都會執(zhí)行
})
// 任何修改都會觸發(fā)
count.value++ // 觸發(fā)
name.value = 'Jane' // 觸發(fā)
age.value = 20 // 觸發(fā)
3. 監(jiān)聽單個 reactive
import { reactive, watchEffect } from 'vue'
const state = reactive({
count: 0,
name: 'John'
})
// 方式1:直接使用整個對象(會深度追蹤所有屬性)
watchEffect(() => {
console.log('state 整體:', state)
// 當(dāng) state 的任何屬性變化時都會觸發(fā)
})
// 方式2:只追蹤特定屬性(性能更好)
watchEffect(() => {
console.log('count 值:', state.count)
// 只有當(dāng) state.count 變化時才觸發(fā)
})
// 修改會觸發(fā)
state.count++ // 觸發(fā)方式1和方式2
state.name = 'Jane' // 只觸發(fā)方式1
4. 監(jiān)聽多個 reactive
import { reactive, watchEffect } from 'vue'
const user = reactive({
name: 'John',
age: 18
})
const settings = reactive({
theme: 'dark',
language: 'zh'
})
// 自動追蹤所有使用的 reactive 屬性
watchEffect(() => {
console.log(`用戶: ${user.name}, ${user.age}歲`)
console.log(`設(shè)置: ${settings.theme}主題, ${settings.language}語言`)
// 當(dāng) user.name、user.age、settings.theme、settings.language 任一變化時觸發(fā)
})
// 修改會觸發(fā)
user.name = 'Jane' // 觸發(fā)
settings.theme = 'light' // 觸發(fā)
5. 混合監(jiān)聽 ref 和 reactive
import { ref, reactive, watchEffect } from 'vue'
const count = ref(0)
const user = reactive({
name: 'John',
info: {
age: 18,
city: 'Beijing'
}
})
// 自動追蹤所有使用的響應(yīng)式數(shù)據(jù)
watchEffect(() => {
console.log(`計數(shù): ${count.value}`)
console.log(`用戶: ${user.name}`)
console.log(`年齡: ${user.info.age}`)
console.log(`城市: ${user.info.city}`)
// 依賴:count.value、user.name、user.info.age、user.info.city
})
// 任何依賴變化都會觸發(fā)
count.value++ // 觸發(fā)
user.name = 'Jane' // 觸發(fā)
user.info.age = 20 // 觸發(fā)
user.info.city = 'Shanghai' // 觸發(fā)
6. 監(jiān)聽嵌套 reactive 對象
import { reactive, watchEffect } from 'vue'
const state = reactive({
user: {
profile: {
name: 'John',
address: {
city: 'Beijing',
street: 'Main St'
}
}
}
})
// 深度追蹤:會自動追蹤所有訪問的嵌套屬性
watchEffect(() => {
console.log('城市:', state.user.profile.address.city)
console.log('街道:', state.user.profile.address.street)
// 只追蹤 city 和 street 的變化
})
// 修改嵌套屬性會觸發(fā)
state.user.profile.address.city = 'Shanghai' // 觸發(fā)
state.user.profile.address.street = 'Nanjing Rd' // 觸發(fā)
// 修改未追蹤的屬性不會觸發(fā)
state.user.profile.name = 'Jane' // 不會觸發(fā)(未在回調(diào)中使用)
7. watchEffect 的清理和停止
import { ref, watchEffect } from 'vue'
const count = ref(0)
// watchEffect 返回停止函數(shù)
const stop = watchEffect((onCleanup) => {
console.log('count:', count.value)
// 清理函數(shù):在重新運行前或停止時執(zhí)行
onCleanup(() => {
console.log('清理副作用')
// 用于取消請求、清除定時器等
})
})
// 停止監(jiān)聽
stop()
8. 異步 watchEffect
import { ref, watchEffect } from 'vue'
const id = ref(1)
const data = ref(null)
watchEffect(async (onCleanup) => {
let cancelled = false
onCleanup(() => {
cancelled = true
})
// 模擬異步請求
const response = await fetch(`/api/data/${id.value}`)
if (!cancelled) {
data.value = await response.json()
}
})
9. 控制執(zhí)行時機(jī)
import { ref, watchEffect } from 'vue'
const count = ref(0)
// flush: 'pre' (默認(rèn)) - 組件更新前執(zhí)行
watchEffect(() => {
console.log('pre:', count.value)
}, {
flush: 'pre'
})
// flush: 'post' - 組件更新后執(zhí)行
watchEffect(() => {
console.log('post:', count.value)
}, {
flush: 'post'
})
// flush: 'sync' - 同步執(zhí)行
watchEffect(() => {
console.log('sync:', count.value)
}, {
flush: 'sync'
})
10. watchEffect vs watch 對比
import { ref, reactive, watch, watchEffect } from 'vue'
const count = ref(0)
const state = reactive({ name: 'John', age: 18 })
// watch: 顯式指定數(shù)據(jù)源
watch(count, (newVal, oldVal) => {
console.log('watch - count:', newVal, oldVal)
})
watch(
[() => state.name, () => state.age],
([newName, newAge], [oldName, oldAge]) => {
console.log('watch - name/age:', newName, newAge)
}
)
// watchEffect: 自動追蹤依賴
watchEffect(() => {
console.log('watchEffect - count:', count.value)
console.log('watchEffect - name/age:', state.name, state.age)
// 自動追蹤 count.value、state.name、state.age
})
// 執(zhí)行時機(jī)
// watch: 懶執(zhí)行,只有數(shù)據(jù)變化時才執(zhí)行
// watchEffect: 立即執(zhí)行一次,然后依賴變化時執(zhí)行
實際應(yīng)用示例
import { ref, reactive, watchEffect } from 'vue'
// 用戶搜索示例
const searchKeyword = ref('')
const filters = reactive({
category: 'all',
sortBy: 'date',
priceRange: [0, 1000]
})
const results = ref([])
// 自動搜索:任何搜索條件變化時自動執(zhí)行
watchEffect(async () => {
console.log('搜索條件變化,重新獲取數(shù)據(jù)')
// 構(gòu)建查詢參數(shù)
const params = {
keyword: searchKeyword.value,
category: filters.category,
sortBy: filters.sortBy,
minPrice: filters.priceRange[0],
maxPrice: filters.priceRange[1]
}
// 模擬 API 請求
const response = await fetch(`/api/search?${new URLSearchParams(params)}`)
results.value = await response.json()
})
// 任何條件變化都會觸發(fā)搜索
searchKeyword.value = 'vue' // 觸發(fā)搜索
filters.category = 'books' // 觸發(fā)搜索
filters.sortBy = 'rating' // 觸發(fā)搜索
filters.priceRange = [0, 500] // 觸發(fā)搜索
總結(jié)對比
| 特性 | watch | watchEffect |
|---|---|---|
| 數(shù)據(jù)源 | 顯式指定 | 自動追蹤依賴 |
| 執(zhí)行時機(jī) | 懶執(zhí)行(首次不執(zhí)行) | 立即執(zhí)行 |
| 舊值獲取 | ? 可以獲取 | ? 無法獲取 |
| 監(jiān)聽多個 | 需要數(shù)組 | 自動收集 |
| 嵌套對象 | 需要 deep 選項 | 自動深度追蹤(訪問到的屬性) |
| 性能優(yōu)化 | 更精確控制 | 自動優(yōu)化 |
最佳實踐
使用 watchEffect 當(dāng):
- 不需要獲取舊值
- 依賴關(guān)系簡單且自動
- 需要立即執(zhí)行副作用
使用 watch 當(dāng):
- 需要獲取舊值
- 需要精確控制監(jiān)聽的數(shù)據(jù)源
- 需要懶執(zhí)行(首次不執(zhí)行)
性能優(yōu)化:
// ? 避免:訪問過多屬性導(dǎo)致頻繁執(zhí)行
watchEffect(() => {
console.log(state) // 任何屬性變化都觸發(fā)
})
// ? 推薦:只訪問需要的屬性
watchEffect(() => {
console.log(state.name, state.age) // 只有這些屬性變化才觸發(fā)
})
以上就是一文詳解vue3 watchEffect監(jiān)聽的各種姿勢用法的詳細(xì)內(nèi)容,更多關(guān)于vue3 watchEffect監(jiān)聽用法的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue編寫可顯示周和月模式的日歷 Vue自定義日歷內(nèi)容的顯示
這篇文章主要為大家詳細(xì)介紹了Vue編寫可顯示周和月模式的日歷,Vue自定義日歷內(nèi)容的顯示,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06
vue中實現(xiàn)拖動調(diào)整左右兩側(cè)div的寬度的示例代碼
這篇文章主要介紹了vue中實現(xiàn)拖動調(diào)整左右兩側(cè)div的寬度的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
解決npm安裝錯誤:No matching version found for&
這篇文章主要介紹了解決npm安裝錯誤:No matching version found for XXX@3.3.6問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
Vue form表單動態(tài)添加組件實戰(zhàn)案例
這篇文章主要介紹了Vue form表單動態(tài)添加組件實戰(zhàn)案例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
解決vue中修改了數(shù)據(jù)但視圖無法更新的情況
今天小編就為大家分享一篇解決vue中修改了數(shù)據(jù)但視圖無法更新的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08

