詳解Vue中Computed與watch的用法與區(qū)別
computed
computed只接收一個getter函數(shù)
1、getter必須有返回值
2、computed返回一個只讀響應式ref對象 (只讀、響應式、對象)
注意:omputed只接收一個getter函數(shù)時,返回的只讀對象,也就是不能修改他的返回值!
getter觸發(fā)條件
- 1、computed返回值首次被讀取時
- 2、getter綁定的響應式變量被修改時
<script setup>
import { ref,computed } from 'vue'
const num = ref(1)
//computed返回一個只讀響應式ref對象computedNum
//computedNum是只讀屬性
let computedNum = computed(() => num.value + 1)
</script>
?
<template>
<p> num:{{ num }} </p>
<p>computedNum:{{ computedNum }}</p>
<!-- 修改響應式變量num 觸發(fā)與之綁定的computed的getter-->
<button @click="num++">num++</button>
<!-- computedNum是只讀屬性-->
<button @click="computedNum++">computedNum++</button>
</template>computed同時接收getter函數(shù)對象和setter函數(shù)對象
1、setter函數(shù)對象沒有返回值
2、computed返回一個可讀可寫響應式對象
3、setter函數(shù)對象有參數(shù),是getter的返回值,也是computed的值
4、修改computed返回值,觸發(fā)setter函數(shù)對象執(zhí)行,但不會真正修改computed返回值(setter內(nèi)改變getter計算值就會改變computed返回值)
setter觸發(fā)條件
computed返回值被修改時
實例:
<script setup>
import { ref, computed } from 'vue'
const num = ref(1)
//getter(只讀)
let computedNum = computed(() => num.value + 1)
//getter和setter (可讀可寫)
let computedNum2 = computed({
get: () => num.value + 1,
set: (val) => {
console.log(val);
//setter中修改ref響應式變量num,將觸發(fā)關聯(lián)的num的getter計算
//computedNum和computedNum2的getter同時觸發(fā)
num.value++
}
})
</script>
?
<template>
<p> num:{{ num }} </p>
<p>computedNum:{{ computedNum }}</p>
<p>computedNum2:{{ computedNum2 }}</p>
<button @click="num++">num++</button>
<!-- computedNum是只讀屬性,會有警告提醒 Write operation failed: computed value is readonly-->
<button @click="computedNum++">computedNum++</button>
<!-- computedNum2是可讀可寫屬性-->
<button @click="computedNum2++">computedNum2++</button>
</template>調(diào)試 Computed
使用范圍:僅開發(fā)模式生效
computed的第二參數(shù):帶有 onTrack 和 onTrigger 選項的對象
onTrack:getter關聯(lián)的響應式數(shù)據(jù)時觸發(fā)。onTrigger:getter關聯(lián)的響應式數(shù)據(jù)被修改時觸發(fā)
<script setup>
import { ref, computed } from 'vue'
const num = ref(1)
let computedNum = computed(() => num.value + 1, {
onTrack: (e) => {
console.log('onTrack');
console.log(e);
},
onTrigger: (e) => {
console.log('onTrigger');
console.log(e);
}
})
?
</script>
?
<template>
<p> num:{{ num }} </p>
<p>computedNum:{{ computedNum }}</p>
<!--每次 num++將觸發(fā)onTrigger -->
<button @click="num++">num++</button>
</template>watchEffect
語法:
- 參數(shù)1:觸發(fā)監(jiān)聽回調(diào)函數(shù),回調(diào)函數(shù)可傳入一個onInvalidate函數(shù)作為參數(shù)!
- 可選參數(shù)2:對象,包含3個可選屬性flush、onTrack、onTrigger
立即執(zhí)行傳入的一個函數(shù),同時響應式追蹤其依賴,并在其依賴變更時重新運行該函數(shù)。
1、會立即執(zhí)行一次(和watch的immediate屬性效果一致)
2、關聯(lián)的響應式數(shù)據(jù)被修改時觸發(fā)
3、會自動感知代碼依賴,和watch不一樣,watchEffect會主動綁定監(jiān)聽數(shù)據(jù)
局限性:不能監(jiān)聽對象(但可以監(jiān)聽對象的屬性),只能監(jiān)聽類似ref基本數(shù)據(jù)類型的響應式數(shù)據(jù)
立即執(zhí)行 監(jiān)聽基本數(shù)據(jù)類型
<script setup>
import { ref, watchEffect } from 'vue'
const num = ref(1)
//會立即執(zhí)行一次
watchEffect(() => {
console.log('watchEffect');
num.value++
})
</script>
?
<template>
<p>num: {{ num }}</p>
<button @click="num++">num++</button>
</template>停止watchEffect
隱式:組件卸載時自動停止
顯式:調(diào)用watchEffect 返回值
const stop = watchEffect(() => {
/* ... */
})
?
// 顯式停止
stop()清理watchEffect
語法: watchEffect( onInvalidate=>{ onInvalidate(()=>{ }) })
onInvalidate 是一個函數(shù)!優(yōu)先觸發(fā)!
onInvalidate 執(zhí)行時機:
1、watchEffect被重新觸發(fā)時
2、組件卸載時
注意:關聯(lián)的響應式數(shù)據(jù)首次被修改時不會觸發(fā)onInvalidate函數(shù)!
作用: 清理定時器、事件監(jiān)聽removeEventListener 。。。
import { ref, watchEffect } from 'vue'
const num = ref(1)
watchEffect((onInvalidate ) => {
console.log('watchEffect-1');
num.value++
onInvalidate (()=>{
console.log('onInvalidate-2');
})
console.log('watchEffect-3');
})
?
//1、watchEffect 被重新觸發(fā)時
// onInvalidate-2
// watchEffect-1
// watchEffect-3
//2、組件卸載時
// onInvalidate-2
//3、關聯(lián)的響應式數(shù)據(jù)首次被修改(組件被掛載時)
// watchEffect-1
// watchEffect-3watchPostEffect 和 watchSyncEffect
watchPostEffect 和 watchSyncEffect在Vue3.2新增,是watchEffect類似語法糖的東西,
是watchEffect可選參數(shù)對象{ flush?: 'pre' | 'post' | 'sync'}中post和sync的語法糖,pre是默認值
推遲觸發(fā)watchPostEffect
watchPostEffect 是watchEffect可選參數(shù)對象{flush:'post'}的語法糖
推遲watchEffect觸發(fā)時機!組件更新前觸發(fā)!也就是在生命周期onBeforeUpdate和 onUpdated之間觸發(fā)
語法:
//推遲觸發(fā)watchEffect
watchEffect(
() => {
/* ... */
},
{
flush: 'post'
}
)
//Vue3.2語法糖watchPostEffect
watchPostEffect(()=>{
/* ... */
})實例:
//實驗watchEffect第二參數(shù) flush: 'post'屬性
watchEffect(() => {
console.log("實驗watchEffect第二參數(shù) {flush: 'post'}屬性");
console.log(obj.age);
},{
flush:'post'
})
watchEffect(() => {
console.log("watchEffect正常時機觸發(fā)");
console.log(obj.age);
})
//生命周期onUpdated
onUpdated(()=>{
console.log('onUpdated()');
})
//生命周期onBeforeUpdate
onBeforeUpdate(()=>{
console.log('onBeforeUpdate()');
})修改obj.age時,執(zhí)行結果:
watchEffect正常時機觸發(fā)
onBeforeUpdate()
實驗watchEffect第二參數(shù) {flush: 'post'}屬性
onUpdated()
同步觸發(fā)watchSyncEffect
watchSyncEffect 是watchEffect可選參數(shù)對象{flush:'sync'}的語法糖
強制效果始終同步觸發(fā)!效率低!也就是默認watchEffect之前觸發(fā)
語法:
watchEffect(
() => {
/* ... */
},
{
flush: 'sync'
}
)
//Vue3.2語法糖watchSyncEffect
watchSyncEffect(()=>{
/* ... */
})watchEffect不能監(jiān)聽對象
//假設修改了對象的屬性值-修改了obj.age
const obj = reactive({ name: '小明', age: 18 })
//watchEffect不能監(jiān)聽對象變化
watchEffect(() => {
console.log('watchEffect監(jiān)聽對象變化');
console.log(obj);
})
//watchEffect可以監(jiān)聽對象屬性變化
watchEffect(() => {
console.log('watchEffect監(jiān)聽對象屬性變化');
console.log(obj.age);
})
//watch監(jiān)聽對象變化
watch(obj, (obj) => {
console.log('watch監(jiān)聽對象變化');
console.log(obj);
})總結:watchEffect用來監(jiān)聽能監(jiān)聽基本數(shù)據(jù)類型,不能監(jiān)聽對象,但能監(jiān)聽對象的屬性;watch能監(jiān)聽基本數(shù)據(jù)類型和對象!
watch
語法:
- 參數(shù)1-被監(jiān)聽數(shù)據(jù)(形式:單個數(shù)據(jù)、數(shù)組、帶返回值的回調(diào)函數(shù))
- 參數(shù)2-觸發(fā)監(jiān)聽的回調(diào)函數(shù),無返回值
- 可選參數(shù)3-對象
{immediate: true,deep:true},對象含2個可選參數(shù)和Vue2參數(shù)效果一致
Vue3的watch和Vue2的watch是基本一樣的
1、需要指定監(jiān)聽數(shù)據(jù)
2、惰性,只在被監(jiān)聽數(shù)據(jù)變化時才觸發(fā)(immediate屬性可以設置在初始化的時候觸發(fā))
監(jiān)聽單個數(shù)據(jù)
參數(shù)1被監(jiān)聽數(shù)據(jù)的形式:
1、單個基本數(shù)據(jù)類型;
2、回調(diào)函數(shù):返回值為單個基本數(shù)據(jù)類型;
// 偵聽一個 getter
//被監(jiān)聽數(shù)據(jù)傳入一個帶返回值的回調(diào)函數(shù)
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
)
?
// 直接偵聽一個 ref
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
})監(jiān)聽多個數(shù)據(jù)(傳入數(shù)組)
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
/* ... */
})官方文檔總結
以下代碼截取官方文檔,從TS代碼可以看出很多關于watch和watchEffect函數(shù)參數(shù)和返回值的細節(jié)!
computed
computed只接收一個getter函數(shù)
getter觸發(fā)條件:
1、computed返回值首次被讀取時
2、getter綁定的響應式變量被修改時
computed同時接收getter函數(shù)對象和setter函數(shù)對象
setter觸發(fā)條件:computed返回值被修改時
// 只讀的
function computed<T>(
getter: () => T,
debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>
?
// 可寫的
function computed<T>(
options: {
get: () => T
set: (value: T) => void
},
debuggerOptions?: DebuggerOptions
): Ref<T>
interface DebuggerOptions {
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}watchEffect
- 參數(shù)1-觸發(fā)監(jiān)聽回調(diào)函數(shù),回調(diào)函數(shù)可傳入一個onInvalidate函數(shù)作為參數(shù)!
- 可選參數(shù)2-對象,包含3個可選屬性flush、onTrack、onTrigger
function watchEffect(
effect: (onInvalidate: InvalidateCbRegistrator) => void,
options?: WatchEffectOptions
): StopHandle
?
interface WatchEffectOptions {
flush?: 'pre' | 'post' | 'sync' // 默認:'pre'
onTrack?: (event: DebuggerEvent) => void
onTrigger?: (event: DebuggerEvent) => void
}
?
interface DebuggerEvent {
effect: ReactiveEffect
target: any
type: OperationTypes
key: string | symbol | undefined
}
?
type InvalidateCbRegistrator = (invalidate: () => void) => void
?
type StopHandle = () => voidwatch
- 參數(shù)1-被監(jiān)聽數(shù)據(jù)(形式:單個數(shù)據(jù)、數(shù)組、帶返回值的回調(diào)函數(shù))
- 參數(shù)2-觸發(fā)監(jiān)聽的回調(diào)函數(shù),無返回值
- 參數(shù)3-傳入
{immediate: true,deep:true}對象和Vue2參數(shù)效果一致
// 偵聽單一源
function watch<T>(
source: WatcherSource<T>,
callback: (
value: T,
oldValue: T,
onInvalidate: InvalidateCbRegistrator
) => void,
options?: WatchOptions
): StopHandle
?
// 偵聽多個源
function watch<T extends WatcherSource<unknown>[]>(
sources: T
callback: (
values: MapSources<T>,
oldValues: MapSources<T>,
onInvalidate: InvalidateCbRegistrator
) => void,
options? : WatchOptions
): StopHandle
?
type WatcherSource<T> = Ref<T> | (() => T)
?
type MapSources<T> = {
[K in keyof T]: T[K] extends WatcherSource<infer V> ? V : never
}
?
// 參見 `watchEffect` 共享選項的類型聲明
interface WatchOptions extends WatchEffectOptions {
immediate?: boolean // 默認:false
deep?: boolean
}以上就是詳解Vue中Computed與watch的用法與區(qū)別的詳細內(nèi)容,更多關于Vue Computed watch的資料請關注腳本之家其它相關文章!
相關文章
vuex之this.$store.dispatch()與this.$store.commit()的區(qū)別及說明
這篇文章主要介紹了vuex之this.$store.dispatch()與this.$store.commit()的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06
關于echarts?清空上一次加載的數(shù)據(jù)問題
這篇文章主要介紹了關于echarts?清空上一次加載的數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
瀏覽器事件循環(huán)與vue nextTicket的實現(xiàn)
這篇文章主要介紹了瀏覽器事件循環(huán)(結合vue nextTicket)的實現(xiàn)方法,需要的朋友可以參考下2019-04-04

