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 代理对象。
相关推荐
恋猫de小郭12 分钟前
移动端开发稳了?AI 目前还无法取代客户端开发,小红书的论文告诉你数据
前端·flutter·ai编程
文心快码BaiduComate30 分钟前
百度云与光本位签署战略合作:用AI Agent 重构芯片研发流程
前端·人工智能·架构
闲云一鹤1 小时前
nginx 快速入门教程 - 写给前端的你
前端·nginx·前端工程化
QCY1 小时前
「完全理解」1 分钟实现自己的 Coding Agent
前端·agent·claude
一拳不是超人2 小时前
Electron主窗口弹框被WebContentView遮挡?独立WebContentView弹框方案详解!
前端·javascript·electron
anyup2 小时前
🔥2026最推荐的跨平台方案:H5/小程序/App/鸿蒙,一套代码搞定
前端·uni-app·harmonyos
雮尘3 小时前
如何在非 Claude IDE (TARE、 Cursor、Antigravity 等)下使用 Agent Skills
前端·agent·ai编程
icebreaker3 小时前
Weapp-vite:原生模式之外,多一种 Vue SFC 选择
前端·vue.js·微信小程序
icebreaker3 小时前
重走 Vue 长征路 Weapp-vite:编译链路与 Wevu 运行时原理拆解
前端·vue.js·微信小程序
wuhen_n3 小时前
代码生成:从AST到render函数
前端·javascript·vue.js