ref模板中自动解包为.value值,脚本中需显式.value;reactive模板中直接点访问属性,不支持原始类型,整体赋值会丢失响应性。

在 Vue 模板中,ref 和 reactive 的渲染行为看似一致,实则底层机制不同,这直接影响取值方式、响应性边界以及模板中的使用习惯。
ref 在模板中自动解包,无需 .value
定义为 ref(1) 的响应式变量,在模板中直接写 {{ count }} 即可显示数值,Vue 编译器会在运行时自动读取其 .value。这种“透明解包”仅发生在模板渲染上下文中(包括插值、指令如 v-bind、v-if 等),不适用于 JavaScript 逻辑中。
- ✅ 模板中:
{{ count }}、:disabled="loading"—— 正确,自动取 .value - ❌ 脚本中:
if (count) { ... }—— 错误,必须写count.value - ⚠️ 注意:嵌套对象中 ref 属性不会被深层解包,例如
const obj = reactive({ x: ref(1) }),模板中仍需{{ obj.x.value }}
reactive 对象在模板中按原样访问,无自动解包
reactive({ name: 'Alice', age: 25 }) 返回的是一个代理对象,模板中通过点语法直接访问属性,如 {{ user.name }}。它的响应性基于 Proxy 拦截,所有属性访问都经过响应式追踪,但本身不涉及 .value 概念。
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
- ✅ 模板中:
{{ user.name }}、v-show="user.active"—— 正常工作 - ❌ 不能对 reactive 对象整体赋值:
user = { name: 'Bob' }会丢失响应性(应替换为Object.assign(user, { name: 'Bob' })或逐个赋值) - ⚠️ reactive 不支持原始类型(如字符串、数字),只能包裹对象、数组、Map、Set 等
混合使用时的常见陷阱:ref 包裹 reactive 对象
有时会写 const state = ref(reactive({ ... })),这种嵌套虽可行,但会引入冗余和混淆:
立即学习“前端免费学习笔记(深入)”;
- 模板中仍写
{{ state.name }}(因 ref 自动解包后得到 reactive 对象) - 但脚本中需
state.value.name,违背了 ref “包装单个值”的设计初衷 - 推荐做法:简单状态用 ref,复杂嵌套结构用 reactive;需要响应式引用对象时,直接用
const state = reactive(...)
响应性丢失的典型场景对比
两者在解构、函数参数、for...in 遍历时都可能丢失响应性,但表现略有差异:
-
ref 解构:
const { count } = useCounter()→count是普通数字,不再响应;应改用toRefs()或保持对象访问 -
reactive 解构:
const { name } = user→ 同样丢失响应性;必须用toRefs(user)或始终通过user.name访问 -
函数传参:
foo(refVal)→ 函数内接收的是 ref 实例,需手动 .value;而foo(reactiveObj)传入的是代理对象,属性访问仍响应(但函数内部无法触发依赖收集,除非在副作用中读取)

















