欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3中watchEffect和watch的基礎(chǔ)應(yīng)用詳解

 更新時間:2023年07月24日 11:19:11   作者:周莫申  
watch是一個偵聽器,默認(rèn)是懶偵聽的,即僅在偵聽源發(fā)生變化時才執(zhí)行回調(diào)函數(shù),watchEffect是會自動收集函數(shù)里面變量的響應(yīng)式依賴,本文主要來講講二者的區(qū)別,感興趣的可以了解一下

watchEffect

watchEffect會自動收集函數(shù)里面變量的響應(yīng)式依賴。在初始化的時候watchEffect會自動執(zhí)行一次(這是無法阻止的),之后watchEffect會根據(jù)收集到的響應(yīng)式依賴,在變量發(fā)生改變時就會被觸發(fā)。

接下來看官方的描述:

wactchEffect:立即運行一個函數(shù),同時響應(yīng)式地追蹤其依賴,并在依賴更改時重新執(zhí)行。

類型

?function watchEffect(
? ?effect: (onCleanup: OnCleanup) => void,
? ?options?: WatchEffectOptions
?): StopHandle
??
?type OnCleanup = (cleanupFn: () => void) => void
??
?interface WatchEffectOptions {
? ?flush?: 'pre' | 'post' | 'sync' // 默認(rèn):'pre'
? ?onTrack?: (event: DebuggerEvent) => void
? ?onTrigger?: (event: DebuggerEvent) => void
?}
??
?type StopHandle = () => void

基本使用

下面例子中watchEffect中只有name是響應(yīng)式對像,它會在頁面初始化的時候就執(zhí)行一次用于收集name的響應(yīng)式依賴,changeName事件被觸發(fā)時,name被改變了,對應(yīng)的就會觸發(fā)watchEffect;當(dāng)changeAge觸發(fā)時,因為并沒有在watchEffect中使用age,所以watchEffect沒有收集到對應(yīng)的響應(yīng)式依賴,watchEffect就不會被觸發(fā)。

?<template>
? ?<div id="app">
? ? ?<h2>{{ name }}</h2>
? ? ?<h2>{{ age }}</h2>
? ? ?<button @click="changeName">修改name</button>
? ? ?<button @click="changeAge">修改Age</button>
? ?</div>
?</template>
??
?<script>
?import { watchEffect, defineComponent, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ?//watchEffect:自動收集響應(yīng)式依賴,默認(rèn)初始化就會執(zhí)行一次
? ? ?const name = ref("李四")
? ? ?const age = ref(18)
??
? ? ?watchEffect(() => {
? ? ? ?console.log("name:", name.value);
? ?  })
? ? ?const changeName = () => name.value += "1"
? ? ?const changeAge = () => age.value += 1
??
? ? ?return {
? ? ? ?name,
? ? ? ?age,
? ? ? ?changeName,
? ? ? ?changeAge
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

停止監(jiān)聽

watchEffect會返回一個函數(shù),這個函數(shù)可以用于停止對響應(yīng)式對象的監(jiān)聽,下面例子中當(dāng)age > 25是就會停止監(jiān)聽:

?<template>
? ?<div id="app">
? ? ?<h2>{{ name }}</h2>
? ? ?<h2>{{ age }}</h2>
? ? ?<button @click="changeName">修改name</button>
? ? ?<button @click="changeAge">修改Age</button>
? ?</div>
?</template>
??
?<script>
?import { watchEffect, defineComponent, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ?//watchEffect:自動收集響應(yīng)式依賴,默認(rèn)初始化就會執(zhí)行一次
? ? ?const name = ref("李四")
? ? ?const age = ref(18)
??
? ? ?// wacthEffect會返回一個函數(shù),這個函數(shù)可用于停止所有的wacthEffect的偵聽
? ? ?const stop = watchEffect(() => {
? ? ? ?console.log("userInfo:", name.value,age.value);
? ?  })
??
? ? ?const changeName = () => name.value += "1"
? ? ?const changeAge = () => {
? ? ? ?age.value += 1
? ? ? ?// 當(dāng) age > 25 時停止偵聽
? ? ? ?if(age.value > 25) stop()
? ?  }
??
? ? ?return {
? ? ? ?name,
? ? ? ?age,
? ? ? ?changeName,
? ? ? ?changeAge
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

清除副作用

在使用監(jiān)聽的時候我們可能會向服務(wù)器發(fā)送請求,當(dāng)監(jiān)聽的數(shù)據(jù)頻繁變化時,這種請求就會頻繁觸發(fā),這無疑極大的浪費了服務(wù)器性能。watchEffect第一個參數(shù)就是要運行的副作用函數(shù)。這個副作用函數(shù)的參數(shù)也是一個函數(shù),用來注冊清理回調(diào),下面是官方給的例子:

?watchEffect(async (onCleanup) => {
? ?const { response, cancel } = doAsyncWork(id.value)
? ?// `cancel` 會在 `id` 更改時調(diào)用
? ?// 以便取消之前
? ?// 未完成的請求
? ?onCleanup(cancel)
? ?data.value = await response
?})

執(zhí)行時機

有時候我們需要去監(jiān)聽dome的變化,通過ref拿到的domewatchEffect第一次執(zhí)行時是null,這是因為此時dome還未渲染完成。watchEffec的第二個參數(shù)是一個可選項,其中flush可以用來調(diào)整watchEffect執(zhí)行時機。

下面是官方對flush的描述:

默認(rèn)情況下,偵聽器將在組件渲染之前執(zhí)行。設(shè)置 flush: 'post' 將會使偵聽器延遲到組件渲染之后再執(zhí)行。在某些特殊情況下 (例如要使緩存失效),可能有必要在響應(yīng)式依賴發(fā)生改變時立即觸發(fā)偵聽器。這可以通過設(shè)置 flush: 'sync' 來實現(xiàn)。然而,該設(shè)置應(yīng)謹(jǐn)慎使用,因為如果有多個屬性同時更新,這將導(dǎo)致一些性能和數(shù)據(jù)一致性的問題。

舉個栗子:

默認(rèn)’pre‘:偵聽器會在組件渲染前執(zhí)行,控制臺會輸出兩次,第一次為null,第二次是頁面渲染完成成功獲取到組件的時候,會輸出組件的引用:

?<template>
? ?<div id="app">
? ? ?<h2 ref="name">張三</h2>
? ?</div>
?</template>
??
?<script>
?import { watchEffect, defineComponent, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ? ?// 執(zhí)行時機(flush):'pre' | 'post' | 'sync' // 默認(rèn)'pre'
? ? ? ?const name = ref(null)
? ? ? ?watchEffect(() => {
? ? ? ? ? ?console.log("nameDome:", name.value);
? ? ?  })
? ? ?return {
? ? ? ?name
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

執(zhí)行結(jié)果截圖如下: 我們可以在控制臺上看到wathcEffect在渲染完成之前執(zhí)行了一次,此時的namenull,當(dāng)渲染完成之后name的值發(fā)生了改變,watchEffect再次執(zhí)行,輸出這個節(jié)點:

修改為flush: 'post':它將會使偵聽器延遲到組件渲染之后再執(zhí)行。在某些特殊情況下 (例如要使緩存失效),可能有必要在響應(yīng)式依賴發(fā)生改變時立即觸發(fā)偵聽器。所以控制臺只會輸出一次,輸出的是組件的引用:

?<template>
? ?<div id="app">
? ? ?<h2 ref="name">張三</h2>
? ?</div>
?</template>
??
?<script>
?import { watchEffect, defineComponent, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ? ?// 執(zhí)行時機(flush):'pre' | 'post' | 'sync' // 默認(rèn)'pre'
? ? ? ?const name = ref(null)
? ? ? ?watchEffect(() => {
? ? ? ? ? ?console.log("nameDome:", name.value);
? ? ?  }, {
? ? ? ? ?flush: 'post'
? ? ?  })
??
? ? ?return {
? ? ? ?name
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

執(zhí)行結(jié)果截圖如下: ,延后執(zhí)行之后就不會觸發(fā)一次無意義的監(jiān)聽了

watch

watch是一個偵聽器,默認(rèn)是懶偵聽的,即僅在偵聽源發(fā)生變化時才執(zhí)行回調(diào)函數(shù)。先貼官方文檔

  • watch需要偵聽特定的數(shù)據(jù)源,并在回調(diào)函數(shù)中執(zhí)行副作用;
  • 默認(rèn)情況下watch是懶監(jiān)聽,只有在被監(jiān)聽的數(shù)據(jù)源發(fā)生變化的時候才會執(zhí)行回調(diào);

watch與watchEffect的區(qū)別

  • watch默認(rèn)不會初始化立即執(zhí)行;
  • watch有更具體的說明那些狀態(tài)發(fā)生變化是觸發(fā)偵聽器的執(zhí)行;
  • watch能夠訪問偵聽狀態(tài)變化前后的值;

類型參數(shù)

下面是官網(wǎng)對watch類型的描述:

?// 偵聽單個來源
?function watch<T>(
? ?source: WatchSource<T>,
? ?callback: WatchCallback<T>,
? ?options?: WatchOptions
?): StopHandle
??
?// 偵聽多個來源
?function watch<T>(
? ?sources: WatchSource<T>[],
? ?callback: WatchCallback<T[]>,
? ?options?: WatchOptions
?): StopHandle

watch一共有三個參數(shù),分別是:source、callbackoptions,options為可選參數(shù)。

soure

soure是一個WatchSource<T>類型,該類型規(guī)定了soure可以是ref對象、reactive對象、數(shù)組對象、函數(shù)(getter)和普通對象:

?type WatchSource<T> =
? ?| Ref<T> // ref
? ?| (() => T) // getter
? ?| T extends object
? ?? T
?  : never // 響應(yīng)式對象

callback

watch的第二個參數(shù)callbackwatch執(zhí)行的回調(diào),這個函數(shù)有三個參數(shù),分別是vaule(新值)、oldValue(舊值)、onCleanup函數(shù)(用于清除副作用),下面是官網(wǎng)對于watch回調(diào)函數(shù)的描述:

?type WatchCallback<T> = (
? ?value: T,
? ?oldValue: T,
? ?onCleanup: (cleanupFn: () => void) => void
?) => void

options

options是可選配置項。我們通過下面接口的描述看到它是繼承至WatchEffectOptions的。immediate可以控制watch在組件初始化是是否執(zhí)行,默認(rèn)值是false。

deep是控制是否開啟深度監(jiān)聽的參數(shù),watch在監(jiān)聽雜的對象時只對表層進(jìn)行監(jiān)聽,默認(rèn)值是false,如果對象的屬性還是一個對像,那么這個對象只要地址不改變watch是不會觸發(fā)的,通過deep: true可以監(jiān)聽到深層對象的改變,需要注意的是:1、當(dāng)watch監(jiān)聽的是一個reactive對象時會自動開啟深度監(jiān)聽;2、如果回調(diào)函數(shù)是因為深度監(jiān)聽的變更而觸發(fā)的,那么valueoldValue將會是同一個對象。

flushwatchEffect一樣的flush,用于控制觸發(fā)實機,默認(rèn)pre,在組件渲染之前執(zhí)行,下面是官網(wǎng)的描述:

?interface WatchOptions extends WatchEffectOptions {
? ?immediate?: boolean // 默認(rèn):false
? ?deep?: boolean // 默認(rèn):false
? ?flush?: 'pre' | 'post' | 'sync' // 默認(rèn):'pre'
? ?onTrack?: (event: DebuggerEvent) => void
? ?onTrigger?: (event: DebuggerEvent) => void
?}

基本使用

我將通過source傳參的不同來舉例watch的基本使用:

傳入ref響應(yīng)式對象

當(dāng)監(jiān)聽的是ref對象時,callbackvalueoldValue獲得的是ref對象對應(yīng)的value值:

?<template>
? ?<div id="app">
? ? ?<h2>{{ name }}</h2>
? ? ?<button @click="changeName">改變用戶數(shù)據(jù)</button>
? ?</div>
?</template>
??
?<script>
?import { watch, defineComponent, reactive, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ? //  傳入ref對象,newValue和oldValue是對應(yīng)的value值
? ? ? const name = ref('張三')
? ? ? watch(name, (newVlaue,oldValue) => {
? ? ? ? console.log('name:',newVlaue,oldValue);
? ? ? })
? ? ?const changeName = ()=>{
? ? ? ?name.value += "1"
? ?  }
? ? ?return {
? ? ? ?name,
? ? ? ?changeName
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

偵聽多個來源,callback會接收兩個數(shù)組,對應(yīng)的順序是偵聽數(shù)組的順序,為了更直觀我做了解構(gòu),也可以寫成(newValue,oldValue)的形式:

?<template>
? ?<div id="app">
? ? ?<h2>{{ name }}</h2>
? ? ?<h2>{{ age }}</h2>
? ? ?</h2>
? ? ?<button @click="changeInfo">改變用戶數(shù)據(jù)</button>
? ?</div>
?</template>
??
?<script>
?import { watch, defineComponent, reactive, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ? //  傳入多個對象,newValue和oldValue是對應(yīng)的value值
? ? ? const name = ref('張三')
? ? ? const age = ref(18)
? ? ? watch([name,age], ([newName,newAge],[oldName,oldAge]) => {
? ? ? ? console.log('new:',newName,newAge,'old',oldName,oldAge);
? ? ? })
? ? ?const changeInfo = ()=>{
? ? ? ?name.value += "1"
? ? ? ?age.value += 1
? ?  }
? ? ?return {
? ? ? ?name,
? ? ? ?age,
? ? ? ?changeInfo
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

傳入reactive對象,callback對應(yīng)的valueoldValue都將是reactive對象,下面userInfo是一個reactive對象,所以newValueoldValue都會是reactive對象:

?<template>
? ?<div id="app">
? ? ?<h2>{{ userInfo.name }}</h2>
? ? ?<h2>{{ userInfo.age }}</h2>
? ? ?<button @click="changeInfo">改變用戶數(shù)據(jù)</button>
? ?</div>
?</template>
??
?<script>
?import { watch, defineComponent, reactive, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ?const userInfo = reactive({ name: '張三', age: 18 })
? ? ?// 傳入reactive對象
? ? ? watch(userInfo, (newValue, oldValue) => {
? ? ? ? ? console.log('userInfo',newValue,oldValue);
? ? ? })
? ? ?const changeInfo = ()=>{
? ? ? ?userInfo.name += "1"
? ? ? ?userInfo.age += 1
? ?  }
? ? ?return {
? ? ? ?userInfo,
? ? ? ?changeInfo
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

如果我們不希望得到響應(yīng)式的newValueoldValue,那么我們可以使用getter函數(shù)傳參方式對reactive進(jìn)行解構(gòu):

?<template>
? ?<div id="app">
? ? ?<h2>{{ userInfo.name }}</h2>
? ? ?<h2>{{ userInfo.age }}</h2>
? ? ?<button @click="changeInfo">改變用戶數(shù)據(jù)</button>
? ?</div>
?</template>
??
?<script>
?import { watch, defineComponent, reactive, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ?const userInfo = reactive({ name: '張三', age: 18 })
? ? ?// 如果不希望newValue和oldValue是reactive對象可以在傳入時對它進(jìn)行解構(gòu)
? ? ?watch(() => { return {...userInfo} }, (newValue, oldValue) => {
? ? ? ?console.log('userInfo:',newValue,oldValue);
? ?  })
? ? ?const changeInfo = ()=>{
? ? ? ?userInfo.name += "1"
? ? ? ?userInfo.age += 1
? ?  }
? ? ?return {
? ? ? ?userInfo,
? ? ? ?changeInfo
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

傳入getter函數(shù),下面摘自官網(wǎng)的描述:"當(dāng)使用 getter 函數(shù)作為源時,回調(diào)只在此函數(shù)的返回值變化時才會觸發(fā)。如果你想讓回調(diào)在深層級變更時也能觸發(fā),你需要使用 { deep: true } 強制偵聽器進(jìn)入深層級模式。在深層級模式時,如果回調(diào)函數(shù)由于深層級的變更而被觸發(fā),那么新值和舊值將是同一個對象。"

?<template>
? ?<div id="app">
? ? ?<h2>{{ userInfo.name }}</h2>
? ? ?<h2>{{ userInfo.age }}</h2>
? ? ?<button @click="changeInfo">改變用戶數(shù)據(jù)</button>
? ?</div>
?</template>
??
?<script>
?import { watch, defineComponent, reactive, ref } from "vue";
??
?export default defineComponent({
? ?setup() {
? ? ?const userInfo = reactive({ name: '張三', age: 18 })
??
? ? ?// 二、傳入getter函數(shù)形式
? ? ?watch(() => userInfo.name, (newVlaue,oldValue) => {
? ? ? ?console.log('newValue',newVlaue,'oldValue',oldValue)
? ?  })
??
? ? ?const changeInfo = ()=>{
? ? ? ?userInfo.name += "1"
? ? ? ?userInfo.age += 1
? ?  }
? ? ?return {
? ? ? ?userInfo,
? ? ? ?changeInfo
? ?  }
?  },
?});
?</script>
??
?<style scoped></style>

以上就是Vue3中watchEffect和watch的基礎(chǔ)應(yīng)用詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue3 watchEffect和watch的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue2.0 自定義 餅狀圖 (Echarts)組件的方法

    vue2.0 自定義 餅狀圖 (Echarts)組件的方法

    下面小編就為大家分享一篇vue2.0 自定義 餅狀圖 (Echarts)組件的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • vue2.0+vuex+localStorage代辦事項應(yīng)用實現(xiàn)詳解

    vue2.0+vuex+localStorage代辦事項應(yīng)用實現(xiàn)詳解

    本篇文章給大家分享了一個用vue2.0+vuex+localStorage代辦事項應(yīng)用實現(xiàn)的代碼過程,有興趣的朋友跟著參考學(xué)習(xí)下。
    2018-05-05
  • Vue 創(chuàng)建組件的兩種方法小結(jié)(必看)

    Vue 創(chuàng)建組件的兩種方法小結(jié)(必看)

    Vue 創(chuàng)建組件的方法有哪些呢?下面小編就為大家分享一篇Vue 創(chuàng)建組件的兩種方法小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • Vue + Webpack + Vue-loader學(xué)習(xí)教程之功能介紹篇

    Vue + Webpack + Vue-loader學(xué)習(xí)教程之功能介紹篇

    這篇文章主要介紹了關(guān)于Vue + Webpack + Vue-loader功能介紹的相關(guān)資料,文中介紹的非常詳細(xì),相信對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-03-03
  • 分享vue里swiper的一些坑

    分享vue里swiper的一些坑

    這篇文章主要介紹了vue里swiper的一些坑及swiper在vue中的使用,本文分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-08-08
  • vue頁面加載閃爍問題的解決方法

    vue頁面加載閃爍問題的解決方法

    這篇文章主要介紹了vue頁面加載閃爍問題的解決方法,文中給大家提到了v-if 和 v-show 的區(qū)別,解決vue頁面加載時出現(xiàn){{message}}閃退的兩種方法,感興趣的朋友一起看看吧
    2018-03-03
  • Vue中的混入的使用(vue mixins)

    Vue中的混入的使用(vue mixins)

    這篇文章主要介紹了Vue中的混入的使用(vue mixins),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • 解決vite項目Uncaught Syntaxerror:Unexpected token>vue項目上線白屏問題

    解決vite項目Uncaught Syntaxerror:Unexpected token>vue項

    這篇文章主要介紹了解決vite項目Uncaught Syntaxerror:Unexpected token>vue項目上線白屏問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • vue3.0+element表格獲取每行數(shù)據(jù)代碼示例

    vue3.0+element表格獲取每行數(shù)據(jù)代碼示例

    這篇文章主要給大家介紹了關(guān)于vue3.0+element表格獲取每行數(shù)據(jù)的相關(guān)資料,在element-ui中,你可以通過為表格的行綁定單擊事件來獲取表格中的一行數(shù)據(jù),需要的朋友可以參考下
    2023-09-09
  • Vue3中Slot插槽透傳,二次封裝Arco的table組件詳解

    Vue3中Slot插槽透傳,二次封裝Arco的table組件詳解

    這篇文章主要介紹了Vue3中Slot插槽透傳,二次封裝Arco的table組件,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04

最新評論