跳轉到內容

響應性 API:核心

另請參閱

為了更好地理解響應性 API,建議閱讀指南中的以下章節

ref()

接收一個內部值並返回一個響應性和可變的 ref 物件,該物件具有一個指向內部值的單屬性 .value

  • 型別

    ts
    function ref<T>(value: T): Ref<UnwrapRef<T>>
    
    interface Ref<T> {
      value: T
    }
  • 詳情

    ref 物件是可變的 - 即您可以分配新的值給 .value。它也是響應性的 - 即對 .value 的任何讀取操作都會被跟蹤,寫入操作將觸發相關效果。

    如果將物件分配為 ref 的值,則物件會透過 reactive() 被轉換為深度響應性。這也意味著如果物件包含巢狀的 ref,它們將被深度展開。

    為了避免深度轉換,請使用 shallowRef()

  • 示例

    js
    const count = ref(0)
    console.log(count.value) // 0
    
    count.value = 1
    console.log(count.value) // 1
  • 另請參閱

computed()

接收一個 getter 函式 並返回一個只讀響應性 ref 物件,該物件包含從 getter 返回的值。它還可以接收一個具有 getset 函式的物件來建立可寫的 ref 物件。

  • 型別

    ts
    // read-only
    function computed<T>(
      getter: (oldValue: T | undefined) => T,
      // see "Computed Debugging" link below
      debuggerOptions?: DebuggerOptions
    ): Readonly<Ref<Readonly<T>>>
    
    // writable
    function computed<T>(
      options: {
        get: (oldValue: T | undefined) => T
        set: (value: T) => void
      },
      debuggerOptions?: DebuggerOptions
    ): Ref<T>
  • 示例

    建立只讀計算 ref

    js
    const count = ref(1)
    const plusOne = computed(() => count.value + 1)
    
    console.log(plusOne.value) // 2
    
    plusOne.value++ // error

    建立可寫計算 ref

    js
    const count = ref(1)
    const plusOne = computed({
      get: () => count.value + 1,
      set: (val) => {
        count.value = val - 1
      }
    })
    
    plusOne.value = 1
    console.log(count.value) // 0

    除錯

    js
    const plusOne = computed(() => count.value + 1, {
      onTrack(e) {
        debugger
      },
      onTrigger(e) {
        debugger
      }
    })
  • 另請參閱

reactive()

返回物件的響應式代理。

  • 型別

    ts
    function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
  • 詳情

    響應式轉換是“深層”的:它影響所有巢狀屬性。響應式物件在保持響應性的同時,也會深度展開任何引用屬性。

    需要注意的是,當引用作為響應式陣列或原生集合型別(如Map)的元素訪問時,不會執行引用展開。

    為了避免深度轉換並僅在根級別保留響應性,請使用shallowReactive()

    返回的物件及其巢狀物件被ES Proxy包裝,並且與原始物件不等價。建議僅使用響應式代理並避免依賴於原始物件。

  • 示例

    建立響應式物件

    js
    const obj = reactive({ count: 0 })
    obj.count++

    引用展開

    ts
    const count = ref(1)
    const obj = reactive({ count })
    
    // ref will be unwrapped
    console.log(obj.count === count.value) // true
    
    // it will update `obj.count`
    count.value++
    console.log(count.value) // 2
    console.log(obj.count) // 2
    
    // it will also update `count` ref
    obj.count++
    console.log(obj.count) // 3
    console.log(count.value) // 3

    請注意,當引用作為陣列或集合元素訪問時,引用不會被展開

    js
    const books = reactive([ref('Vue 3 Guide')])
    // need .value here
    console.log(books[0].value)
    
    const map = reactive(new Map([['count', ref(0)]]))
    // need .value here
    console.log(map.get('count').value)

    當將引用賦值給reactive屬性時,該引用也將自動展開

    ts
    const count = ref(1)
    const obj = reactive({})
    
    obj.count = count
    
    console.log(obj.count) // 1
    console.log(obj.count === count.value) // true
  • 另請參閱

readonly()

接受一個物件(響應式或純物件)或一個引用,並返回對原始物件的只讀代理。

  • 型別

    ts
    function readonly<T extends object>(
      target: T
    ): DeepReadonly<UnwrapNestedRefs<T>>
  • 詳情

    只讀代理是深層的:訪問的任何巢狀屬性也將是隻讀的。它還具有與reactive()相同的引用展開行為,除了展開的值也將變為只讀。

    為了避免深度轉換,請使用shallowReadonly()

  • 示例

    js
    const original = reactive({ count: 0 })
    
    const copy = readonly(original)
    
    watchEffect(() => {
      // works for reactivity tracking
      console.log(copy.count)
    })
    
    // mutating original will trigger watchers relying on the copy
    original.count++
    
    // mutating the copy will fail and result in a warning
    copy.count++ // warning!

watchEffect()

立即執行一個函式,同時響應式地跟蹤其依賴項,並在依賴項更改時重新執行它。

  • 型別

    ts
    function watchEffect(
      effect: (onCleanup: OnCleanup) => void,
      options?: WatchEffectOptions
    ): WatchHandle
    
    type OnCleanup = (cleanupFn: () => void) => void
    
    interface WatchEffectOptions {
      flush?: 'pre' | 'post' | 'sync' // default: 'pre'
      onTrack?: (event: DebuggerEvent) => void
      onTrigger?: (event: DebuggerEvent) => void
    }
    
    interface WatchHandle {
      (): void // callable, same as `stop`
      pause: () => void
      resume: () => void
      stop: () => void
    }
  • 詳情

    第一個引數是要執行的效應函式。效應函式接收一個函式,可用於註冊清理回撥。清理回撥將在下一次效應重新執行之前被呼叫,並可用於清理無效的副作用,例如掛起的非同步請求(見以下示例)。

    第二個引數是一個可選的選項物件,可用於調整效應的重新整理時間或除錯效應的依賴項。

    預設情況下,觀察者將在元件渲染之前執行。將flush: 'post'設定為將觀察者推遲到元件渲染之後。有關更多資訊,請參閱回撥重新整理時間。在罕見的情況下,可能需要在響應式依賴項更改時立即觸發觀察者,例如,以使快取無效。這可以透過使用flush: 'sync'來實現。然而,此設定應謹慎使用,因為它可能導致在同時更新多個屬性時出現效能和資料一致性方面的問題。

    返回值是一個處理函式,可以呼叫它以停止效應再次執行。

  • 示例

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

    停止觀察者

    js
    const stop = watchEffect(() => {})
    
    // when the watcher is no longer needed:
    stop()

    暫停/恢復觀察者:

    js
    const { stop, pause, resume } = watchEffect(() => {})
    
    // temporarily pause the watcher
    pause()
    
    // resume later
    resume()
    
    // stop
    stop()

    副作用清理

    js
    watchEffect(async (onCleanup) => {
      const { response, cancel } = doAsyncWork(newId)
      // `cancel` will be called if `id` changes, cancelling
      // the previous request if it hasn't completed yet
      onCleanup(cancel)
      data.value = await response
    })

    3.5+中的副作用清理

    js
    import { onWatcherCleanup } from 'vue'
    
    watchEffect(async () => {
      const { response, cancel } = doAsyncWork(newId)
      // `cancel` will be called if `id` changes, cancelling
      // the previous request if it hasn't completed yet
      onWatcherCleanup(cancel)
      data.value = await response
    })

    選項

    js
    watchEffect(() => {}, {
      flush: 'post',
      onTrack(e) {
        debugger
      },
      onTrigger(e) {
        debugger
      }
    })
  • 另請參閱

watchPostEffect()

watchEffect()的別名,帶有flush: 'post'選項。

watchSyncEffect()

watchEffect()的別名,帶有flush: 'sync'選項。

watch()

觀察一個或多個響應式資料來源,並在資料來源更改時呼叫回撥函式。

  • 型別

    ts
    // watching single source
    function watch<T>(
      source: WatchSource<T>,
      callback: WatchCallback<T>,
      options?: WatchOptions
    ): WatchHandle
    
    // watching multiple sources
    function watch<T>(
      sources: WatchSource<T>[],
      callback: WatchCallback<T[]>,
      options?: WatchOptions
    ): WatchHandle
    
    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) // reactive object
    
    interface WatchOptions extends WatchEffectOptions {
      immediate?: boolean // default: false
      deep?: boolean | number // default: false
      flush?: 'pre' | 'post' | 'sync' // default: 'pre'
      onTrack?: (event: DebuggerEvent) => void
      onTrigger?: (event: DebuggerEvent) => void
      once?: boolean // default: false (3.4+)
    }
    
    interface WatchHandle {
      (): void // callable, same as `stop`
      pause: () => void
      resume: () => void
      stop: () => void
    }

    為了可讀性,型別已簡化。

  • 詳情

    watch() 預設是懶載入的 - 即只有當被觀察的源發生變化時,回撥才會被呼叫。

    第一個引數是觀察者的 。源可以是以下之一

    • 一個返回值的 getter 函式
    • 一個 ref
    • 一個響應式物件
    • ...或者以上任意型別的陣列。

    第二個引數是在源發生變化時被呼叫的回撥函式。回撥函式接收三個引數:新值、舊值以及一個用於註冊副作用清理回撥函式的函式。清理回撥函式將在下一次副作用重新執行之前被呼叫,可以用來清理無效的副作用,例如掛起的非同步請求。

    當觀察多個源時,回撥函式接收包含新/舊值的兩個陣列,這些值對應於源陣列。

    第三個可選引數是一個支援以下選項的選項物件

    • immediate:在觀察者建立時立即觸發回撥。第一次呼叫時,舊值將是 undefined
    • deep:如果源是物件,強制進行深度遍歷,以便在深度突變時觸發回撥。在 3.5+ 中,這也可以是一個表示最大遍歷深度的數字。參見 深度觀察者
    • flush:調整回撥的重新整理時間。參見 回撥重新整理時間watchEffect()
    • onTrack / onTrigger:除錯觀察者的依賴關係。參見 觀察者除錯
    • once:(3.4+)只執行一次回撥。第一次回撥執行後,觀察者將自動停止。

    watchEffect() 相比,watch() 允許我們

    • 懶載入副作用;
    • 更具體地指定哪些狀態應該觸發觀察者重新執行;
    • 訪問被觀察狀態的當前值和舊值。
  • 示例

    觀察 getter

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

    觀察 ref

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

    當觀察多個源時,回撥函式接收包含新/舊值的陣列,這些值對應於源陣列

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

    當使用 getter 源時,只有當 getter 的返回值發生變化時,觀察者才會觸發。如果您希望在深度突變時觸發回撥,需要顯式地將觀察者強制進入深度模式,使用 { deep: true }。注意,在深度模式下,如果回撥是由深度突變觸發的,新值和舊值將是相同的物件

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

    當直接觀察響應式物件時,觀察者自動處於深度模式

    js
    const state = reactive({ count: 0 })
    watch(state, () => {
      /* triggers on deep mutation to state */
    })

    watch()watchEffect() 具有相同的重新整理時間和除錯選項

    js
    watch(source, callback, {
      flush: 'post',
      onTrack(e) {
        debugger
      },
      onTrigger(e) {
        debugger
      }
    })

    停止觀察者

    js
    const stop = watch(source, callback)
    
    // when the watcher is no longer needed:
    stop()

    暫停/恢復觀察者:

    js
    const { stop, pause, resume } = watch(() => {})
    
    // temporarily pause the watcher
    pause()
    
    // resume later
    resume()
    
    // stop
    stop()

    副作用清理

    js
    watch(id, async (newId, oldId, onCleanup) => {
      const { response, cancel } = doAsyncWork(newId)
      // `cancel` will be called if `id` changes, cancelling
      // the previous request if it hasn't completed yet
      onCleanup(cancel)
      data.value = await response
    })

    3.5+中的副作用清理

    js
    import { onWatcherCleanup } from 'vue'
    
    watch(id, async (newId) => {
      const { response, cancel } = doAsyncWork(newId)
      onWatcherCleanup(cancel)
      data.value = await response
    })
  • 另請參閱

onWatcherCleanup()

註冊一個清理函式,在當前觀察者即將重新執行時執行。只能在同步執行 watchEffect 副作用函式或 watch 回撥函式時呼叫(即不能在非同步函式中的 await 語句之後呼叫。)

  • 型別

    ts
    function onWatcherCleanup(
      cleanupFn: () => void,
      failSilently?: boolean
    ): void
  • 示例

    ts
    import { watch, onWatcherCleanup } from 'vue'
    
    watch(id, (newId) => {
      const { response, cancel } = doAsyncWork(newId)
      // `cancel` will be called if `id` changes, cancelling
      // the previous request if it hasn't completed yet
      onWatcherCleanup(cancel)
    })
響應性 API:核心已載入