响应式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