亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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、callbackoptionsoptions為可選參數(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)聽雜的對象時只對表層進行監(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進行解構(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對象可以在傳入時對它進行解構(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 } 強制偵聽器進入深層級模式。在深層級模式時,如果回調(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)文章

  • Vue3實現(xiàn)動態(tài)導(dǎo)入Excel表格數(shù)據(jù)的方法詳解

    Vue3實現(xiàn)動態(tài)導(dǎo)入Excel表格數(shù)據(jù)的方法詳解

    在開發(fā)工作過程中,我們會遇到各種各樣的表格數(shù)據(jù)導(dǎo)入,動態(tài)數(shù)據(jù)導(dǎo)入可以減少人為操作,減少出錯。本文為大家介紹了Vue3實現(xiàn)動態(tài)導(dǎo)入Excel表格數(shù)據(jù)的方法,需要的可以參考一下
    2022-11-11
  • 詳解webpack + vue + node 打造單頁面(入門篇)

    詳解webpack + vue + node 打造單頁面(入門篇)

    本篇文章主要介紹了詳解webpack + vue + node 打造單頁面(入門篇) ,非常具有實用價值,需要的朋友可以參考下
    2017-09-09
  • Vue 全局loading組件實例詳解

    Vue 全局loading組件實例詳解

    這篇文章主要介紹了Vue 全局loading組件,需要的朋友可以參考下
    2018-05-05
  • vue打包之后配置統(tǒng)一請求地址步驟詳解

    vue打包之后配置統(tǒng)一請求地址步驟詳解

    這篇文章主要為大家介紹了vue打包之后配置統(tǒng)一請求地址實現(xiàn)步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-07-07
  • vue中beforeRouteLeave實現(xiàn)頁面回退不刷新的示例代碼

    vue中beforeRouteLeave實現(xiàn)頁面回退不刷新的示例代碼

    這篇文章主要介紹了vue中beforeRouteLeave實現(xiàn)頁面回退不刷新的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 詳解如何在Vue2中實現(xiàn)組件props雙向綁定

    詳解如何在Vue2中實現(xiàn)組件props雙向綁定

    在Vue2中組件的props的數(shù)據(jù)流動改為了只能單向流動,如何在Vue2中實現(xiàn)組件props雙向綁定 ,一起來跟小編看看。
    2017-03-03
  • Vue實現(xiàn)固定底部組件的示例

    Vue實現(xiàn)固定底部組件的示例

    本文主要介紹了Vue實現(xiàn)固定底部組件的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Vue?中插槽的使用總結(jié)

    Vue?中插槽的使用總結(jié)

    這篇文章主要向大家分享的是Vue?中插槽的使用總結(jié),包括內(nèi)容有默認(rèn)插槽、具名插槽、作用域插槽等內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-04-04
  • vue router使用query和params傳參的使用和區(qū)別

    vue router使用query和params傳參的使用和區(qū)別

    本篇文章主要介紹了vue router使用query和params傳參的使用和區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • 前端Vue3項目打包成Docker鏡像運行的詳細(xì)步驟

    前端Vue3項目打包成Docker鏡像運行的詳細(xì)步驟

    將Vue3項目打包、編寫Dockerfile、構(gòu)建Docker鏡像和運行容器是部署Vue3項目到Docker的主要步驟,這篇文章主要介紹了前端Vue3項目打包成Docker鏡像運行的詳細(xì)步驟,需要的朋友可以參考下
    2024-09-09

最新評論