customRef 用于完全控制 ref 的 getter 和 setter 行为,适用于防抖、localStorage 同步、异步缓存等场景;需手动调用 track() 和 trigger(),避免无限循环与响应丢失。

customRef 是 Vue 3 响应式系统中一个灵活但较少被直接使用的 API,它允许你**完全控制 ref 的 getter 和 setter 行为**,从而实现更精细的响应式逻辑,比如防抖、节流、惰性求值、缓存、或与外部状态(如 localStorage、Web Worker)同步。
什么时候该用 customRef?
当你发现 ref 或 computed 无法满足特定响应式需求时,例如:
- 希望某个值在修改后延迟更新(如输入框防抖)
- 需要读取时才计算、且结果可缓存(避免重复开销)
- 想让 ref 自动与本地存储保持双向同步
- 要拦截并校验每次赋值(类似受控组件 + 自定义验证)
customRef 的基本结构
它接收一个工厂函数,该函数返回一个包含 get 和 set 方法的对象:
track() 和 trigger() 手动通知依赖更新)```js
import { customRef } from 'vue'
function useDebouncedRef(value, delay = 200) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track() // 告诉 Vue:当前副作用依赖这个 ref
return value
},
set(newValue) {
clearTimeout(timeout)
timeout = setTimeout(() => {
value = newValue
trigger() // 告诉 Vue:值变了,更新依赖
}, delay)
}
}
})
}
```
立即学习“前端免费学习笔记(深入)”;
常见实用封装示例
1. localStorage 同步 ref
让 ref 值自动持久化,并在其他标签页变更时也能响应:
- get 中读取 localStorage 并 track
- set 中写入 localStorage 并 trigger
- 监听 storage 事件,跨标签页触发 trigger
2. 可取消的异步 ref(如 fetch 结果缓存)
在 get 中判断是否已加载;set 支持传入 Promise,内部自动处理 loading / error 状态,并支持 cancelToken 防止过期回调。
3. 带格式化/解析的 ref(如金额输入)
set 接收原始字符串,内部转为数字并校验;get 返回格式化后的显示值(如带千分位),但内部仍保存原始数值用于计算。
注意事项和陷阱
- 必须在
get中调用track(),否则依赖不会收集,值变化也不更新视图 - 必须在
set中调用trigger(),否则依赖不会重新执行 - 不要在 get/set 中直接调用其他 ref 的 value —— 容易引发无限循环或丢失响应性
- 如果内部状态需要被多个 customRef 共享,建议用闭包变量 + 显式 trigger,而非依赖外部 ref


















