ref适用于基础类型、单值模板直连或需整体替换的数据,如count=ref(0);reactive专用于对象/数组,支持深层响应式,如user=reactive({name:''}),直接访问属性且默认深度监听。

ref 和 reactive 是 Vue 3 响应式系统的两个基石,不是“选一个用”,而是“按需组合用”。关键不在孰优孰劣,而在数据形态、访问方式、更新粒度与内存开销之间的精准匹配。
什么时候该用 ref
适合基础类型(数字、字符串、布尔)、需要模板直连的单值、或需频繁整体替换的数据:
- 计数器、开关状态、表单输入绑定:如 const count = ref(0)、const isActive = ref(false)
- 模板中直接插值或绑定:{{ count }}、:class="{ active: isActive }" —— Vue 自动解包,无需 .value
- 需要整个替换对象/数组:比如 list.value = apiResponse.data,响应性依然保留
- 跨 setup 边界共享(如 provide/inject、composable 返回值):ref 天然可传递,避免 reactive 解构后失活
什么时候该用 reactive
专为对象和数组设计,适合结构稳定、深层嵌套、属性频繁读写的复杂状态:
重要:对 React 或 Next.js 代码的任何更改必须先阅读本技能。Vercel 工程团队的 React 与 Next.js 指南,涵盖可视化...
- 用户信息、表单模型、配置对象:如 const user = reactive({ name: '', age: 0, address: { city: '' } })
- 直接访问属性更简洁:user.name、user.address.city,JS 和模板写法一致
- 深度响应式默认开启:修改嵌套字段(user.address.city = 'Beijing')仍触发更新
- 注意:不能用于基础类型;也不能直接赋新对象,如 user = { name: 'Tom' } 会彻底丢失响应性
解构、性能与内存调优关键点
响应式不是免费的,深层代理有开销。大型数据结构要主动降级:
- 解构 reactive 对象会断开响应链:用 const { name } = toRefs(user) 保持每个字段可响应
- 只读场景用 readonly():保护 props、computed 返回值,防止误改且减少依赖追踪
- 超大 JSON 或编辑器文档树?用 shallowRef 或 shallowReactive:仅代理第一层,手动触发更新(data.value = newData)
- 第三方类实例(如 Chart.js 图表对象)用 markRaw() 包裹:跳过响应式转换,避免 Proxy 污染和性能损耗
计算与监听的协同策略
ref 和 reactive 不是孤立存在的,要搭配 computed、watch、watchEffect 构建完整响应流:
- computed 接收 ref 或 reactive 属性,返回缓存的派生值,适合模板内多次使用
- watch 明确监听 ref 或 reactive 的某个路径(如 watch(() => user.name, ...)),支持 immediate 和 deep,适合发请求、操作 DOM
- watchEffect 自动收集依赖,写法轻量,但不支持旧值、不自动 deep —— 需要监听嵌套变化时,手动展开字段或改用 watch










