響應式API:高階
shallowRef()
是ref()
的淺層版本。
型別
tsfunction shallowRef<T>(value: T): ShallowRef<T> interface ShallowRef<T> { value: T }
詳情
與
ref()
不同,淺層引用的內部值直接儲存和暴露,不會變為深層響應式。只有.value
訪問是響應式的。shallowRef()
通常用於大型資料結構的效能最佳化或與外部狀態管理系統的整合。示例
jsconst state = shallowRef({ count: 1 }) // does NOT trigger change state.value.count = 2 // does trigger change state.value = { count: 2 }
另請參閱
triggerRef()
根據淺引用(shallow ref)觸發相關效果。這通常在修改淺引用內部值之後使用。
型別
tsfunction triggerRef(ref: ShallowRef): void
示例
jsconst shallow = shallowRef({ greet: 'Hello, world' }) // Logs "Hello, world" once for the first run-through watchEffect(() => { console.log(shallow.value.greet) }) // This won't trigger the effect because the ref is shallow shallow.value.greet = 'Hello, universe' // Logs "Hello, universe" triggerRef(shallow)
customRef()
建立一個具有顯式控制其依賴跟蹤和更新觸發的自定義引用。
型別
tsfunction customRef<T>(factory: CustomRefFactory<T>): Ref<T> type CustomRefFactory<T> = ( track: () => void, trigger: () => void ) => { get: () => T set: (value: T) => void }
詳情
customRef()
期望一個工廠函式,該函式接收track
和trigger
函式作為引數,並應返回一個具有get
和set
方法的物件。通常,
track()
應在get()
內部呼叫,而trigger()
應在set()
內部呼叫。然而,您可以完全控制它們何時呼叫,或者是否呼叫它們。示例
建立一個防抖引用,僅在最新設定呼叫後的特定超時後更新值
jsimport { customRef } from 'vue' export function useDebouncedRef(value, delay = 200) { let timeout return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } } }) }
元件中使用
vue<script setup> import { useDebouncedRef } from './debouncedRef' const text = useDebouncedRef('hello') </script> <template> <input v-model="text" /> </template>
謹慎使用
使用自定義引用時,我們應該小心其getter的返回值,尤其是在每次執行getter時生成新的物件資料型別時。這影響了父元件和子元件之間的關係,其中這種自定義引用被作為prop傳遞。
父元件的渲染函式可能由不同響應式狀態的更改觸發。在重新渲染期間,我們自定義引用的值會被重新評估,返回一個新的物件資料型別作為prop傳遞給子元件。子元件將此prop與其最後一個值進行比較,由於它們不同,子元件中自定義引用的響應式依賴項被觸發。同時,父元件中的響應式依賴項沒有執行,因為自定義引用的setter沒有被呼叫,其依賴項也沒有被觸發。
shallowReactive()
淺版本的reactive()
。
型別
tsfunction shallowReactive<T extends object>(target: T): T
詳情
與
reactive()
不同,沒有深度轉換:淺響應式物件的根級屬性是響應式的。屬性值按原樣儲存和公開 - 這也意味著具有ref值的屬性將不會自動解包。謹慎使用
淺資料結構應僅用於元件的根級狀態。避免將其巢狀在深度響應式物件中,因為它建立了一個具有不一致響應性行為的樹,這可能會很難理解和除錯。
示例
jsconst state = shallowReactive({ foo: 1, nested: { bar: 2 } }) // mutating state's own properties is reactive state.foo++ // ...but does not convert nested objects isReactive(state.nested) // false // NOT reactive state.nested.bar++
shallowReadonly()
淺版本的readonly()
。
型別
tsfunction shallowReadonly<T extends object>(target: T): Readonly<T>
詳情
與
readonly()
不同,沒有深度轉換:只有根級屬性被設定為只讀。屬性值按原樣儲存和公開 - 這也意味著具有ref值的屬性將不會自動解包。謹慎使用
淺資料結構應僅用於元件的根級狀態。避免將其巢狀在深度響應式物件中,因為它建立了一個具有不一致響應性行為的樹,這可能會很難理解和除錯。
示例
jsconst state = shallowReadonly({ foo: 1, nested: { bar: 2 } }) // mutating state's own properties will fail state.foo++ // ...but works on nested objects isReadonly(state.nested) // false // works state.nested.bar++
toRaw()
返回Vue建立的代理的原始物件。
型別
tsfunction toRaw<T>(proxy: T): T
詳情
toRaw()
可以從由reactive()
、readonly()
、shallowReactive()
或shallowReadonly()
建立的代理中返回原始物件。這是一個逃生艙,可用於在不產生代理訪問/跟蹤開銷的情況下暫時讀取,或在不觸發更改的情況下寫入。不建議持久引用原始物件。請謹慎使用。
示例
jsconst foo = {} const reactiveFoo = reactive(foo) console.log(toRaw(reactiveFoo) === foo) // true
markRaw()
標記一個物件,使其永遠不會轉換為代理。返回物件本身。
型別
tsfunction markRaw<T extends object>(value: T): T
示例
jsconst foo = markRaw({}) console.log(isReactive(reactive(foo))) // false // also works when nested inside other reactive objects const bar = reactive({ foo }) console.log(isReactive(bar.foo)) // false
謹慎使用
markRaw()
和淺層 API,如shallowReactive()
,允許您選擇性地退出預設的深度響應式/只讀轉換,並將原始、非代理物件嵌入到您的狀態圖中。它們可以用作各種原因某些值根本不應該變成響應式的,例如複雜的第三方類例項或 Vue 元件物件。
當渲染包含不可變資料來源的大型列表時,跳過代理轉換可以提高效能。
它們被認為是高階的,因為原始的退出僅在根級別,所以如果您將一個巢狀的、未標記的原始物件設定到響應式物件中,然後再次訪問它,您會得到代理版本。這可能導致 身份風險 - 即執行依賴於物件身份的操作,但使用同一物件的原始和代理版本
jsconst foo = markRaw({ nested: {} }) const bar = reactive({ // although `foo` is marked as raw, foo.nested is not. nested: foo.nested }) console.log(foo.nested === bar.nested) // false
身份風險通常很少見。然而,為了安全地避免身份風險並正確使用這些 API,需要對反應性系統的工作方式有一個深刻的理解。
effectScope()
建立一個效果作用域物件,可以捕獲其中建立的響應式效果(即計算屬性和監視器),以便可以將這些效果一起丟棄。有關此 API 的詳細用法,請參閱其相應的 RFC。
型別
tsfunction effectScope(detached?: boolean): EffectScope interface EffectScope { run<T>(fn: () => T): T | undefined // undefined if scope is inactive stop(): void }
示例
jsconst scope = effectScope() scope.run(() => { const doubled = computed(() => counter.value * 2) watch(doubled, () => console.log(doubled.value)) watchEffect(() => console.log('Count: ', doubled.value)) }) // to dispose all effects in the scope scope.stop()
getCurrentScope()
如果有,則返回當前活動的 效果作用域。
型別
tsfunction getCurrentScope(): EffectScope | undefined
onScopeDispose()
在當前活動的 效果作用域 上註冊一個銷燬回撥。當關聯的效果作用域停止時,將呼叫此回撥。
此方法可以用作可複用組合函式中 onUnmounted
的非元件耦合替代品,因為每個 Vue 元件的 setup()
函式也是在效果作用域內呼叫的。
如果沒有活動的作用域就呼叫此函式,將丟擲一個警告。在 3.5+ 中,可以透過將 true
作為第二個引數傳遞來抑制此警告。
型別
tsfunction onScopeDispose(fn: () => void, failSilently?: boolean): void