Vue 3 中 computed
與 watch
深度解析
在 Vue 3 組合中,響應式工具的類型安全使用至關重要。以下是詳細說明
一、watch
偵聽器
1. 基礎類型監聽
<template><div>實際參數1={{count}}</div><div><button @click="count++">點擊</button></div>
</template><script setup lang="ts">
import {reactive,ref,watch
} from "vue";const count = ref<number>(0)
const state = reactive({items: [] as string[]});watch(count, (newVal:number, oldVal:number) => {state.items.push(String(count.value))console.log('newVal, oldVal === ', newVal, oldVal)
})watch(() => state.items, () => {console.log('state.items ===', state.items)
},{deep: true})</script>
2. 多源監聽
<template><div>實際參數1={{count}}</div><div><button @click="count++">點擊</button></div>
</template><script setup lang="ts">
import {reactive,ref,watch
} from "vue";const count = ref<number>(0)
const state = reactive({items: [] as string[]});watch(count, (newVal:number, oldVal:number) => {state.items.push(String(count.value))console.log('newVal, oldVal === ', newVal, oldVal)
})watch(() => state.items, () => {console.log('state.items ===', state.items)
},{deep: true})watch([count, state], ([newCount, newState]:[number, object], [oldCount, oldState]:[number, object])=> {console.log('[newCount, newState], [oldCount, oldState] =', newCount, newState, oldCount, oldState)
})
</script>
3. 深度監聽對象
<template><div>實際參數1={{product}}</div><div><button @click="product.price++">點擊</button></div>
</template><script setup lang="ts">
import {reactive,watch
} from "vue";
interface Product {id: number,price: number,name: string,specs: {color: string,weight: number}
}const product = reactive<Product>({id: 1,price: 131,name: 'Bwm',specs: {color: 'red',weight: 80}
})watch(() => product.price, // 創建新引用觸發深度監聽(newProduct,oldProduct) => {console.log('newVal,oldVal === ', newProduct,oldProduct)},{deep: true})
</script>
二、watchEffect
高級用法
watchEffect() 允許我們自動跟蹤回調的響應式依賴,且會立即執行。
1. 基本用法
<template><div>實際參數1={{product}}</div><div><button @click="product.price++">點擊</button></div>
</template><script setup lang="ts">
import {reactive,ref,watch, watchEffect
} from "vue";
interface Product {id: number,price: number,name: string,specs: {color: string,weight: number}
}const product = reactive<Product>({id: 1,price: 131,name: 'Bwm',specs: {color: 'red',weight: 80}
})
const totalPrice = ref<number>(0)watchEffect(()=> {totalPrice.value = product.price + 2console.log('totalPrice === ', totalPrice)
})
</script>
2. 清理副作用
<template><div>實際參數1={{product}}</div><div><button @click="product.price+=10">點擊</button></div>
</template><script setup lang="ts">
import {reactive,ref,watchEffect,onWatcherCleanup
} from "vue";interface Product {id: number,price: number,name: string,specs: {color: string,weight: number}
}const product = reactive<Product>({id: 1,price: 131,name: 'Bwm',specs: {color: 'red',weight: 80}
})
const totalPrice = ref<number>(0)watchEffect(()=> {totalPrice.value = product.price + 2console.log('totalPrice === ', totalPrice)onWatcherCleanup(() => {console.log('onWatcherCleanup ===')})
})
</script>
三、computed
計算屬性
1. 對象類型計算
<template><div>實際參數1={{totalPrice}}</div><div><button @click="product.price+=10">點擊</button></div>
</template><script setup lang="ts">
import {reactive,ref,computed
} from "vue";
interface Product {id: number,price: number,name: string,specs: {color: string,weight: number}
}const product = reactive<Product>({id: 1,price: 131,name: 'Bwm',specs: {color: 'red',weight: 80}
})
const totalPrice = computed<number>(()=>product.price += 10)
</script>
2. 可寫計算屬性
<template><div>{{fullName}}</div><div>姓名: <el-input v-model="fullName"/></div>
</template><script setup lang="ts">
import {reactive,ref,computed
} from "vue";
const firstName = ref<string>('Jane')
const lastName = ref<string>('Smith')const fullName = computed<string>({get() {return `${firstName.value} ${lastName.value}`},set(fullName:string) {const [newFirstName, newLastName] = fullName.split(' ')firstName.value = newFirstNamelastName.value = newLastName}
})
</script>
四、computed
vs watch
vs watchEffect
對比
特性 | computed | watch | watchEffect |
---|---|---|---|
目的 | 派生值 | 響應變化執行操作 | 自動追蹤依賴執行操作 |
返回值 | ref對象 | 停止函數 | 停止函數 |
初始化執行 | 立即計算 | 可配置(immediate) | 立即執行 |
依賴聲明 | 自動 | 顯式指定 | 自動 |
緩存 | ? | ? | ? |
異步支持 | ? | ? | ? |
清理機制 | ? | ? | ? |
調試鉤子 | ? | ? | ? |
適合場景 | 數據轉換/格式化 | 精確控制的操作 | 自動追蹤依賴的副作用 |
總結
-
computed
:- 用于派生狀態
- 具有緩存機制
- 適合數據轉換和格式化
- 模板中優先使用
-
watch
:- 用于執行副作用
- 提供精確控制
- 適合異步操作、DOM操作
- 需要顯式聲明依賴
-
watchEffect
:- 自動追蹤依賴
- 立即執行
- 適合多個依賴的簡單副作用
- 提供清理機制
黃金法則:
- 需要派生值 → 用
computed
- 需要響應變化執行操作 → 用
watch
或watchEffect
- 需要精確控制依賴 → 用
watch
- 需要自動追蹤多個依賴 → 用
watchEffect
- 避免在
computed
中產生副作用 - 總是在副作用中清理資源
通過合理選擇和使用這些 API,可以構建出高效、可維護的 Vue 3 應用程序。