shallowRef,triggerRef和customRef()

在 Vue 3 的响应式系统中,shallowReftriggerRef 和 customRef() 是用于精细化控制响应性行为的高级 API。它们适用于需要对响应式更新进行细粒度控制的场景。


🧩 一、shallowRef

✅ 作用:

创建一个 仅追踪 .value 引用变化 的 ref,不会对对象内部属性进行深层响应式转换

示例:

import { shallowRef, watchEffect } from 'vue'

const state = shallowRef({
  count: 0,
  user: { name: 'Alice' }
})

watchEffect(() => {
  console.log('state.value:', state.value)
})

state.value.count++ // 不会触发 watchEffect 更新
state.value = { count: 1 } // 会触发更新

❗只有当整个 .value 被替换时才会触发更新。


🔁 二、triggerRef

✅ 作用:

手动触发一个 shallowRef 的依赖更新。常用于你修改了 shallowRef 内部状态但不想或不能替换整个 .value 时。

示例:

import { shallowRef, triggerRef } from 'vue'

const obj = shallowRef({ count: 0 })

obj.value.count++
triggerRef(obj) // 手动触发更新

⚠️ triggerRef 只能用于 shallowRef 或使用 customRef 自定义行为的对象。


🛠 三、customRef()

✅ 作用:

自定义一个 ref 的响应式行为,允许你完全控制 track(依赖收集)和 trigger(触发更新)逻辑。

使用场景:

  • 实现防抖/节流的 ref
  • 延迟更新
  • 外部数据源同步
  • 需要精细控制响应式的复杂场景

示例:实现一个带防抖功能的 ref

useDebouncedRef 函数的返回值是一个 ref 对象,它具有 .value 属性,并且其行为符合 Vue 的响应式系统规则。

    import { customRef } from 'vue'
    import { debounce } from 'lodash-es'
    
    export function useDebouncedRef(value, delay = 200) {
      return customRef((track, trigger) => {
        let currentValue = value
    
        const debouncedTrigger = debounce(() => {
          trigger() // 触发响应式更新
        }, delay)
    
        return {
          get() {
            track() // 收集依赖
            return currentValue
          },
          set(newValue) {
            currentValue = newValue
            debouncedTrigger()
          }
        }
      })
    }

    ✅ 返回值说明:

    • customRef() 是 Vue 提供的一个 API,用于创建一个自定义行为的 ref
    • 它返回的是一个 带有 .value 属性的对象
    • 这个对象可以像普通 ref 一样使用:
    const searchQuery = useDebouncedRef('');
    console.log(searchQuery.value); // 获取值
    searchQuery.value = 'hello';     // 设置值
    使用方式:
    const searchQuery = useDebouncedRef('') <input v-model="searchQuery" />

    因为 Vue 模板中的 v-model 会自动解包 ref(即自动读取 .value 并在赋值时调用 .set())。 

    这是 Vue 3 的特性之一:在模板中使用 ref 时,会自动解包 .value。 

    同样的逻辑也适用于 v-model,所以你可以放心地把 ref 对象传给 v-model。 

    表达式是否正确说明
    useDebouncedRef('') 返回值是 ref 对象✅ 正确例如 { value: '...' }
    <input v-model="searchQuery" /> 绑定该对象✅ 正确Vue 模板会自动解包 .value
    v-model 是否要求必须是原始值?❌ 否可以是 ref 对象,Vue 会自动处理

    🎯 此输入框的值会在用户停止输入后 200ms 才触发响应式更新。


    📊 对比总结表

    API特点适用场景
    ref深层响应式,自动解包嵌套 ref默认首选,通用响应式
    shallowRef仅响应 .value 变化,不处理内部结构性能敏感、大对象优化
    triggerRef手动触发 shallowRef 更新修改内部属性后主动刷新
    customRef()完全自定义响应式行为高级定制,如防抖、异步加载

    💡 最佳实践建议

    • 默认使用 ref,除非你有明确的性能或行为控制需求。
    • 性能敏感场景(如大型对象、频繁局部更新)使用 shallowRef + triggerRef
    • 需要精确控制响应式更新时机(如搜索框防抖)时使用 customRef()
    • 避免滥用 triggerRef,它破坏了 Vue 的自动依赖追踪机制,应谨慎使用。
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值