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 代理对象。
相关推荐
anOnion13 分钟前
Agentic 前端开发之 实时显示 AI Agent 终端输出
前端·javascript·人工智能
随风一样自由23 分钟前
【前端领域】2026最新前端领域全梳理(框架/工具/AI/跨端/底层标准/就业趋势)
前端·人工智能·前端框架
这是个栗子23 分钟前
【前端性能优化】优化数据加载:用 Promise.all 从串行到并行
前端·javascript·性能优化·异步编程·前端优化·promise.all
fei_sun1 小时前
黑洞路由(Null Route/空接口路由)
服务器·前端·javascript
大爱一家盟1 小时前
告别卡点BGM同质化 2026原创卡点音乐素材下载网站 TOP5 推荐
大数据·前端·人工智能
彦为君1 小时前
算法思维与经典智力题
java·前端·redis·算法
aa小小2 小时前
localhost 访问异常排查笔记
前端
格子软件2 小时前
2026年GEO优化系统源码的分布式状态机深度拆解
java·前端·vue.js·vue·geo
陈随易2 小时前
Rust、Golang、MoonBit 编译成 WASM,体积和速度差距有多大?
前端·后端·程序员
IT_陈寒2 小时前
Python多线程的坑,我居然现在才踩到
前端·人工智能·后端