Vue3中ref与reactive的区别

在 Vue 3 中,refreactive 是两种不同的响应式数据创建方式,它们的区别和实现方式如下:


一、核心区别

特性 ref reactive
适用类型 基本类型 + 对象类型 仅对象类型(对象/数组/Map/Set)
访问方式 通过 .value 访问 直接访问属性
解构响应性 需要 toRefs 保持解构后的响应性 直接解构会丢失响应性
深层响应性 自动递归代理嵌套对象 自动递归代理嵌套对象
模板自动解包 支持(模板中无需 .value 直接访问属性

二、实现方式

1. ref 的实现
  • 核心机制 :通过一个对象包装值(RefImpl 类),利用 getter/setter + Proxy 实现响应式。

  • 源码关键点

js 复制代码
class RefImpl<T> {
   private _value: T
 private _rawValue: T // 原始值(避免对象被 reactive 二次代理)
   
   constructor(value: T) {
     this._rawValue = value
     this._value = isObject(value) ? reactive(value) : value
   }
   
   get value() {
     track(this, TrackOpTypes.GET, 'value') // 依赖收集
     return this._value
   }
   
   set value(newVal) {
     if (hasChanged(newVal, this._rawValue)) {
       this._rawValue = newVal
       this._value = isObject(newVal) ? reactive(newVal) : newVal
       trigger(this, TriggerOpTypes.SET, 'value') // 触发更新
     }
   }
 }
  • 特点

    • 对基本类型直接通过 getter/setter 监听。
    • 对对象类型内部使用 reactive 代理。
2. reactive 的实现
  • 核心机制 :基于 Proxy 代理对象,拦截 get/set/deleteProperty 等操作。

  • 源码关键点

js 复制代码
function reactive(target) {
   const proxy = new Proxy(target, {
   get(target, key, receiver) {
       track(target, TrackOpTypes.GET, key) // 依赖收集
       const res = Reflect.get(target, key, receiver)
       return isObject(res) ? reactive(res) : res // 递归代理嵌套对象
     },
     set(target, key, value, receiver) {
       const oldValue = target[key]
       const result = Reflect.set(target, key, value, receiver)
       if (hasChanged(value, oldValue)) {
         trigger(target, TriggerOpTypes.SET, key) // 触发更新
       }
       return result
     }
   })
   return proxy
 }
  • 特点

    • 通过 Proxy 实现深层响应式。
    • 递归代理嵌套对象(性能优化可通过 shallowReactive 避免)。

三、使用场景

1. 使用 ref 的场景
  • 需要响应式的基本类型值(如 string/number/boolean)。
  • 需要显式控制值的引用(如需要重新赋值整个对象时)。
  • 需要兼容模板自动解包(模板中无需 .value)。
2. 使用 reactive 的场景
  • 需要响应式的复杂对象或数组。
  • 需要保持对象引用不变,仅修改属性。
  • 需要深层响应式(如嵌套对象自动代理)。

四、最佳实践

  1. 优先选择 ref

    对于基本类型或需要频繁重新赋值的对象,使用 ref 更直观。

  2. 复杂对象用 reactive

    当需要处理嵌套结构且不需要重新赋值整个对象时,reactive 更简洁。

  3. 解构时用 toRefs

    解构 reactive 对象时,使用 toRefs 保持响应性:

js 复制代码
const state = reactive({ count: 0 })
 const { count } = toRefs(state) // 解构后仍为 Ref 类型

五、底层原理对比

机制 ref reactive
依赖收集 通过 getter 中的 track 通过 Proxy.get 中的 track
触发更新 通过 setter 中的 trigger 通过 Proxy.set 中的 trigger
性能开销 基本类型更低,对象类型与 reactive 相同 对象类型高效,嵌套对象递归代理

总结

  • ref :更通用的响应式工具,通过 .value 访问,适合基本类型或需要重新赋值的对象。
  • reactive:专为对象设计的响应式工具,适合深层嵌套结构,直接访问属性更简洁。
  • 实现差异ref 通过 RefImpl 类包装值,reactive 通过 Proxy 代理对象。
相关推荐
M ? A16 分钟前
Vue转React最佳工具对比:Vuera、Veaury与VuReact
前端·javascript·vue.js·经验分享·react.js
We་ct21 分钟前
JS手撕:函数进阶 & 设计模式解析
开发语言·前端·javascript·设计模式·面试·前端框架
悟空瞎说36 分钟前
前端老鸟实战:纯 CSS 实现小红书「真・瀑布流」,零 JS、自动错落、生产可用
前端
yuki_uix37 分钟前
当 reduce 遇到二维数据:从"聚合直觉"到"复合 Map"的思维跃迁
前端·javascript·面试
我叫黑大帅40 分钟前
Vue3中的computed 与 watch 的区别
前端·javascript·面试
暗不需求42 分钟前
# 一文搞懂 JavaScript 内存机制:从栈和堆,到闭包为什么“活得更久”
前端·javascript
CharlesY42 分钟前
JavaScript HTML5 Cache Manifest:离线应用缓存机制考古
前端·javascript
yuki_uix42 分钟前
前端解题的 6 个思维模型:比记答案更有用的东西
前端·面试
Bigger1 小时前
第三章:我是如何剖析 Claude Code 工具系统与命令执行机制的
前端·claude·源码阅读
GISer_Jing1 小时前
告别手搓架构图!Excalidraw+AI Skills 高效绘制手绘风技术图
前端·人工智能·react.js