Vue组合式函数中ref参数易“失活”因解构或直接读value会脱离响应式上下文;应统一用unref()或toValue()配合watchEffect,避免顶层读.value,并显式传入所有依赖ref。

Vue 组合式函数接收 ref 类型参数时,若需在内部建立响应式依赖(比如用 watch 或 watchEffect 监听其变化),必须显式处理,否则会丢失响应式追踪。
为什么 ref 参数容易“失活”?
直接解构或读取 ref.value 会脱离响应式上下文。例如:
❌ 错误写法(失去响应式):
const { value } = propsRef // 解构后 value 是普通值,不响应变化
console.log(propsRef.value) // 仅一次取值,不建立依赖
正确保持响应式的方式
✅ 推荐统一使用 unref() 或 toValue()(Vue 3.4+)配合 watchEffect:
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- 在
watchEffect内部直接使用 ref 参数,Vue 自动追踪其变化 - 需要手动解包时,用
unref(param)—— 它对 ref 返回.value,对普通值原样返回,安全且响应式友好 - 避免在函数体顶层直接读取
param.value,除非你明确不需要响应式联动
实际例子:监听传入的 ID 并触发请求
✅ 正确实现:
立即学习“前端免费学习笔记(深入)”;
export function useUserData(id: Ref<string | number>) {
const data = ref<any>(null)
const loading = ref(false)
watchEffect(async (onInvalidate) => {
loading.value = true
const curId = unref(id) // 安全取值,支持 ref 或普通值
if (!curId) return
const controller = new AbortController()
onInvalidate(() => controller.abort())
data.value = await fetchUser(curId, { signal: controller.signal })
loading.value = false
})
return { data, loading }
}
额外提醒:避免隐式依赖
组合式函数应显式声明所有输入参数,不从外部作用域悄悄读取 ref。例如:
- ❌ 不要这样:
const id = useRoute().params.id写死在函数内 - ✅ 应该这样:
useUserData(route.params.id),把 ref 明确传入

















