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 代理对象。
相关推荐
咔咔库奇9 分钟前
【react】基础教程
前端·react.js·前端框架
前端小王hs11 分钟前
MySQL后端返回给前端的时间变了(时区问题)
前端·数据库·mysql
千篇不一律17 分钟前
工作项目速刷手册
服务器·前端·数据库
天天向上10242 小时前
VSCode 使用import导入js/vue等时添加智能提示,并可跳转到定义
javascript·vue.js·vscode
阿丽塔~2 小时前
vue3 下载文件 responseType-blob 或者 a标签
前端·vue·excel
七灵微3 小时前
【前端】Axios & AJAX & Fetch
前端·javascript·ajax
究极无敌暴龙战神X3 小时前
一篇文章学懂Vuex
前端·javascript·vue.js
院人冲冲冲4 小时前
微前端qiankun打包部署
开发语言·前端·javascript
我命由我123454 小时前
微信小程序 - 页面跳转(wx.navigateTo、wx.redirectTo、wx.switchTab、wx.reLaunch)
前端·微信小程序·小程序·前端框架·html·html5·js