标准答案

  1. customRef 接收 track 和 trigger,读取值时调用 track 收集依赖,合适的时机调用 trigger 通知依赖更新。
  2. 防抖输入场景里,customRef 可以让 v-model 绑定的响应式值在停顿后才真正更新。
  3. watch 防抖通常是值已经变化了,只是把请求、校验、保存等副作用延迟执行。
  4. customRef 改变的是响应式值对外可见的更新时机,watch 防抖改变的是副作用执行时机。
  5. 如果只是防抖请求,优先用 watch 或事件处理防抖;如果需要把防抖能力封装成一个响应式值,再考虑 customRef。

题目解析

这道题的重点是区分“状态更新防抖”和“副作用防抖”。两者表现相似,但对表单、校验和 UI 反馈的影响不同。

customRef 更靠近响应式底层,封装后调用体验很好,但也更容易隐藏真实更新时间。

在复杂表单里,如果输入框显示、校验状态、接口请求都依赖同一字段,要明确哪些部分需要即时响应,哪些部分可以防抖。

代码示例

下面的 customRef 会在输入停止一段时间后再触发依赖更新。

TypeScript
function useDebouncedRef<T>(initialValue: T, delay = 300) {
  let value = initialValue
  let timer: ReturnType<typeof setTimeout> | undefined

  return customRef<T>((track, trigger) => ({
    get() {
      track()
      return value
    },
    set(nextValue) {
      clearTimeout(timer)
      timer = setTimeout(() => {
        value = nextValue
        trigger()
      }, delay)
    }
  }))
}

常见误区

  • 把 customRef 和 watch 防抖说成完全一样,忽略一个控制值更新,一个控制副作用执行。
  • 所有输入都用 customRef 防抖,导致输入框显示、校验和提交状态变得迟钝。
  • 在 customRef 里忘记 track 或 trigger,导致依赖无法收集或视图不更新。

作者信息