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

vue3中watch和watchEffect的區(qū)別

 更新時間:2023年05月23日 09:38:28   作者:泡泡茶壺39  
本文主要介紹了vue3中watch和watchEffect的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

watch和watchEffect

watchEffect()

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

類型

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

詳細信息

  • 第一個參數(shù)就是要運行的副作用函數(shù)。這個副作用函數(shù)的參數(shù)也是一個函數(shù),用來注冊清理回調(diào)。清理回調(diào)會在該副作用下一次執(zhí)行前被調(diào)用,可以用來清理無效的副作用,例如等待中的異步請求 (參見下面的示例)。
  • 第二個參數(shù)是一個可選的選項,可以用來調(diào)整副作用的刷新時機或調(diào)試副作用的依賴。

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

示例

const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 輸出 0
count.value++
// -> 輸出 1

副作用清除:

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

停止偵聽器:

const stop = watchEffect(() => {})
// 當不再需要此偵聽器時:
stop()

選項:

watchEffect(() => {}, {
  flush: 'post'
})

功能及其使用官網(wǎng)寫的清楚,再來了解下它的原理

function watchEffect(
  source: WatchEffect,
  options?: WatchOptionsBase
): WatchStopHandle {
 let getter = () => {
     if (cleanup) {
       cleanup()
     }
     return source(onCleanup)
  }
  let cleanup: () => void
  let onCleanup: OnCleanup = (fn: () => void) => {
    cleanup = effect.onStop = () => fn()
  }
  const job: SchedulerJob = () => {
    if (!effect.active) {
      return
    }
    effect.run()
  }
  let scheduler: EffectScheduler
  if (flush === 'sync') {
    scheduler = job as any
  } else if (flush === 'post') {
    scheduler = () => queuePostRenderEffect(job)
  } else {
    // default: 'pre'
    scheduler = () => queuePreFlushCb(job)
  }
  // 創(chuàng)建 effect
  const effect = new ReactiveEffect(getter, scheduler)
  if (flush === 'post') {
    queuePostRenderEffect(
      effect.run.bind(effect)
    )
  } else {
    effect.run()
  }
  return () => {
    effect.stop()
  }
}

watchEffect的回調(diào)函數(shù)就是一個副作用函數(shù),因為我們使用watchEffect就是偵聽到依賴的變化后執(zhí)行某些操作。什么是副作用(side effect),簡單的說副作用就是執(zhí)行某種操作,如對外部可變數(shù)據(jù)或變量的修改,外部接口的調(diào)用等。

watchEffect內(nèi)部是創(chuàng)建了一個ReactiveEffect對象,接收兩個參數(shù),第一個getter,在執(zhí)行effect.run()時會調(diào)用,第二個scheduler在依賴變化后執(zhí)行。

那我們執(zhí)行watchEffect(() => console.log(count))時,具體做了什么呢,首先創(chuàng)建了個getter,執(zhí)行g(shù)etter做了兩件事,第一個會看有cleanup沒,cleanup會在調(diào)用OnCleanup賦值, 有就執(zhí)行,第二個執(zhí)行source,為watchEffect傳遞的回調(diào)函數(shù),參數(shù)為OnCleanup;然后會創(chuàng)建OnCleanup,這個會在執(zhí)行source時當參數(shù)傳入,當在source里執(zhí)行這個參數(shù),會創(chuàng)建cleanup,這個cleanup的執(zhí)行時機是下一次執(zhí)行前被調(diào)用或停止該副作用時調(diào)用;然后創(chuàng)建scheduler,scheduler主要就是執(zhí)行effect.run()也就是getter,會根據(jù)傳的flush的不同會創(chuàng)建三種執(zhí)行時機不同的scheduler 第一種sync scheduler:為異步執(zhí)行,會在依賴改變時立即執(zhí)行,比如for循環(huán)改變10次依賴就會執(zhí)行10次 第二種 post scheduler:會在組件渲染后執(zhí)行 第三種 pre scheduler:默認,會在組件渲染前執(zhí)行 然后會創(chuàng)建ReactiveEffect,參數(shù)為之前創(chuàng)建getter和scheduler,創(chuàng)建完后接著會根據(jù)傳的flush來執(zhí)行effect.run(),是post會延遲在組件渲染后執(zhí)行,否則就立即執(zhí)行,執(zhí)行effect.run()會觸發(fā)依賴手收集, 最后返回停止該副作用的函數(shù),執(zhí)行會執(zhí)行effect.stop(),這個會觸發(fā)cleanup

wath()

官網(wǎng)介紹:偵聽一個或多個響應(yīng)式數(shù)據(jù)源,并在數(shù)據(jù)源變化時調(diào)用所給的回調(diào)函數(shù)。

類型

// 偵聽單個來源
function watch<T>(
  source: WatchSource<T>,
  callback: WatchCallback<T>,
  options?: WatchOptions
): StopHandle
// 偵聽多個來源
function watch<T>(
  sources: WatchSource<T>[],
  callback: WatchCallback<T[]>,
  options?: WatchOptions
): StopHandle
type WatchCallback<T> = (
  value: T,
  oldValue: T,
  onCleanup: (cleanupFn: () => void) => void
) => void
type WatchSource<T> =
  | Ref<T> // ref
  | (() => T) // getter
  | T extends object
  ? T
  : never // 響應(yīng)式對象
interface WatchOptions extends WatchEffectOptions {
  immediate?: boolean // 默認:false
  deep?: boolean // 默認:false
  flush?: 'pre' | 'post' | 'sync' // 默認:'pre'
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
}

詳細信息

watch() 默認是懶偵聽的,即僅在偵聽源發(fā)生變化時才執(zhí)行回調(diào)函數(shù)。

第一個參數(shù)是偵聽器的源。這個來源可以是以下幾種:

  • 一個函數(shù),返回一個值
  • 一個 ref
  • 一個響應(yīng)式對象
  • ...或是由以上類型的值組成的數(shù)組

第二個參數(shù)是在發(fā)生變化時要調(diào)用的回調(diào)函數(shù)。這個回調(diào)函數(shù)接受三個參數(shù):新值、舊值,以及一個用于注冊副作用清理的回調(diào)函數(shù)。該回調(diào)函數(shù)會在副作用下一次重新執(zhí)行前調(diào)用,可以用來清除無效的副作用,例如等待中的異步請求。

當偵聽多個來源時,回調(diào)函數(shù)接受兩個數(shù)組,分別對應(yīng)來源數(shù)組中的新值和舊值。

第三個可選的參數(shù)是一個對象,支持以下這些選項:

  • immediate:在偵聽器創(chuàng)建時立即觸發(fā)回調(diào)。第一次調(diào)用時舊值是 undefined。
  • deep:如果源是對象,強制深度遍歷,以便在深層級變更時觸發(fā)回調(diào)。參考深層偵聽器。
  • flush:調(diào)整回調(diào)函數(shù)的刷新時機。參考回調(diào)的刷新時機及 watchEffect()。
  • onTrack / onTrigger:調(diào)試偵聽器的依賴。參考調(diào)試偵聽器。

與 watchEffect() 相比,watch() 使我們可以:

  • 懶執(zhí)行副作用;
  • 更加明確是應(yīng)該由哪個狀態(tài)觸發(fā)偵聽器重新執(zhí)行;
  • 可以訪問所偵聽狀態(tài)的前一個值和當前值。

示例
偵聽一個 getter 函數(shù):

const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

偵聽一個 ref:

const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

當偵聽多個來源時,回調(diào)函數(shù)接受兩個數(shù)組,分別對應(yīng)來源數(shù)組中的新值和舊值:

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

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

const state = reactive({ count: 0 })
watch(
  () => state,
  (newValue, oldValue) => {
    // newValue === oldValue
  },
  { deep: true }
)

當直接偵聽一個響應(yīng)式對象時,偵聽器會自動啟用深層模式:

const state = reactive({ count: 0 })
watch(state, () => {
  /* 深層級變更狀態(tài)所觸發(fā)的回調(diào) */
})

watch的功能是完全包含watchEffect的,原理其實是差不多的,主要就是getter和scheduler不同

function watch(
  source: WatchSource | WatchSource[] | WatchEffect | object,
  cb: WatchCallback | null,
  { immediate, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ
): WatchStopHandle {
  let getter: () => any
  if (isRef(source)) {
    getter = () => source.value
  } else if (isReactive(source)) {
    getter = () => source
    deep = true
  } else if (isArray(source)) {
    getter = () =>
      source.map(s => {
        if (isRef(s)) {
          return s.value
        } else if (isReactive(s)) {
          return traverse(s)
        } else if (isFunction(s)) {
          return s()
        }
      })
  } else if (isFunction(source)) {
     getter = () => source()
  }
  if (cb && deep) {
    const baseGetter = getter
    getter = () => traverse(baseGetter())
  }
  let cleanup: () => void
  let onCleanup: OnCleanup = (fn: () => void) => {
    cleanup = effect.onStop = () => {
      fn()
    }
  }
  let oldValue = isMultiSource ? [] : INITIAL_WATCHER_VALUE
  const job: SchedulerJob = () => {
     if (!effect.active) {
       return
     }
     // watch(source, cb)
     const newValue = effect.run()
     if (cleanup) {
         cleanup()
      }
      cb(newValue, oldValue, onCleanup)
      oldValue = newValue
  }
  let scheduler: EffectScheduler
  if (flush === 'sync') {
    scheduler = job as any
  } else if (flush === 'post') {
    scheduler = () => queuePostRenderEffect(job)
  } else {
    // default: 'pre'
    scheduler = () => queuePreFlushCb(job)
  }
  const effect = new ReactiveEffect(getter, scheduler)
  if (immediate) {
    job()
  } else {
    oldValue = effect.run()
  }
?
  return () => {
    effect.stop()
  }
}

首先是getter,可以看到會根據(jù)不同source的類型定義不同的getter,包括Ref、Reactive、Array和function四種,getter就是獲取這些類型返回的值,從而觸發(fā)依賴收集;然后是deep,如果deep為true,會改變getter為() => traverse(baseGetter()),traverse()會遞歸獲取里面的值;onCleanup和watchEffect的一樣;scheduler的執(zhí)行時機和watchEffect一樣,主要就是job不一樣,job主要做兩件事,第一個是執(zhí)行cleanup和watchEffect一樣,第二個是執(zhí)行watch(source, cb)的第二個參數(shù)cb,參數(shù)為newValue和oldValue,newValue為effect.run()也就是getter()的返回值,oldValue為上次執(zhí)行的newValue;同樣也創(chuàng)建了ReactiveEffect對象;然后是immediate,為true執(zhí)行job,job里會執(zhí)行effect.run()收集依賴和cb,否則就執(zhí)行effect.run()收集依賴了;最后watch的返回值和watchEffect一樣。

總的來說watch和watchEffect功能很強大,源碼看起來也不是很難,看完源碼使用起來就更加得心應(yīng)手了。

本文主要記錄看watch和watchEffect源碼的一些筆記,沒有涉及響應(yīng)式的收集依賴和觸發(fā)。

參考vue3官網(wǎng)

到此這篇關(guān)于vue3中watch和watchEffect的區(qū)別的文章就介紹到這了,更多相關(guān)vue3 watch watchEffect內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論