当前位置: 首页 > news >正文

4.2 Vue3中reactive与ref详解及区别

reactiveref 是 Vue 3 Composition API 中创建响应式数据的两个核心函数。它们都基于 Proxy 实现了数据的响应式,但使用场景和方式有所不同。


一、reactive

1. 基本概念

  • 作用:将一个对象(或数组)转换为响应式对象。
  • 原理:使用 Proxy 对传入的对象进行深度代理,拦截其所有属性的读取(get)和设置(set)操作。
  • 返回值:返回一个代理对象(Proxy),该对象是原始对象的响应式副本。

2. 基本用法

import { reactive } from 'vue'// 响应式对象
const state = reactive({count: 0,name: 'Vue',user: {age: 25},list: [1, 2, 3]
})// 直接修改属性
state.count++
state.name = 'Composition API'
state.user.age = 30
state.list.push(4)// 在模板中使用
// <template>
//   <div>{{ state.count }}</div>
//   <div>{{ state.user.age }}</div>
// </template>

3. 特点

  • 只适用于对象/数组:不能用于基本类型(stringnumberbooleannullundefinedsymbol)。
  • 深层响应式:对嵌套对象和数组也是响应式的。
  • 直接访问:在 JavaScript 和模板中都直接通过 . 或 [] 访问属性,无需 .value
  • 代理对象:返回的是一个 Proxy 对象,与原始对象不相等 (state !== originalObject)。

4. 注意事项

  • 解构会失去响应性
    const state = reactive({ count: 0, name: 'Alice' })// ❌ 错误:解构后 count 和 name 是普通变量,失去响应性
    const { count, name } = statecount++ // 不会触发视图更新// ✅ 正确:使用 toRefs
    const { count, name } = toRefs(state)
    // 此时 count 和 name 是 ref,需要 .value
    count.value++ // ✅ 会触发更新
  • 替换整个对象会失去响应性
    const state = reactive({ count: 0 })// ❌ 错误:直接赋值一个新对象,会丢失响应性连接
    state = { count: 1 } // state 不再是响应式的// ✅ 正确:修改对象属性
    state.count = 1// ✅ 正确:如果需要替换,可以重新 reactive
    Object.assign(state, { count: 1, name: 'Bob' })
  • Set/Map/WeakSet/WeakMapreactive 也可以代理这些集合类型。

二、ref

1. 基本概念

  • 作用:创建一个响应式引用。它可以包装任何类型的值(基本类型或对象)。
  • 原理
    • 对于基本类型:创建一个包含 .value 属性的对象,并使用 Object.defineProperty (Vue 2) 或 Proxy (Vue 3) 使其响应式。
    • 对于对象类型:内部会自动调用 reactive() 进行转换。
  • 返回值:返回一个包含 .value 属性的对象

2. 基本用法

import { ref } from 'vue'// 响应式基本类型
const count = ref(0)
const name = ref('Vue')
const isActive = ref(true)// 修改值
count.value++ // 必须使用 .value
name.value = 'Composition API'// 响应式对象 (内部调用 reactive)
const user = ref({age: 25
})
user.value.age = 30 // 注意:user 是 ref,user.value 是 reactive 对象// 响应式数组
const list = ref([1, 2, 3])
list.value.push(4)

3. 特点

  • 通用性强:可以用于任何类型的数据。
  • .value 访问
    • 在 JavaScript 中读取或修改值时,必须使用 .value
    • 在 模板 (template) 中使用时,Vue 会自动解包(unwrapping),无需 .value
    <!-- 模板中 -->
    <template><div>{{ count }}</div>     <!-- 自动解包,显示 count.value --><div>{{ user.age }}</div>  <!-- 自动解包,显示 user.value.age --><button @click="count++">+</button> <!-- 模板中也无需 .value -->
    </template>
  • 解包 (Unwrapping)
    • 当 ref 被作为属性添加到 reactive 对象中时,会自动解包。
      • 在 ref 内部,如果值是对象,也会自动转换为 reactive
    const count = ref(0)
    const state = reactive({count, // 自动解包,state.count 等同于 count.valuename: 'Alice'
    })console.log(state.count) // 0 (直接访问,无需 .value)
    state.count++ // 相当于 count.value++
    console.log(count.value) // 1

4. 注意事项

  • JavaScript 中必须用 .value:忘记 .value 是常见错误。
  • 模板中自动解包:这是 Vue 的优化,让模板更简洁。
  • 数组索引ref 包装的数组,在 JavaScript 中访问元素仍需 .value
    const list = ref([1, 2, 3])
    console.log(list.value[0]) // ✅ 正确
    // console.log(list[0]) // ❌ 错误,list 是 ref 对象,不是数组

三、reactive 与 ref 的核心区别

特性reactive()ref()
适用类型仅对象/数组 (Object, Array, Map, Set 等)任何类型 (基本类型 + 对象/数组)
返回值响应式代理对象 (Proxy)包含 .value 的响应式对象
访问方式 (JS)直接访问属性 (obj.prop)必须通过 .value 访问 (ref.value)
访问方式 (模板)直接访问 ({{ obj.prop }})自动解包,直接访问 ({{ ref }})
解构直接解构会失去响应性 (需 toRefs)解构后仍是 ref,需 .value
替换替换整个对象会失去响应性可以安全地替换 ref.value
性能深层代理,可能稍重基本类型轻量,对象内部用 reactive
类型推断 (TS)类型保持不变包装为 Ref<T>

四、如何选择?

  1. 优先使用 ref

    • 当你不确定数据类型时。
    • 当你需要一个基本类型的响应式变量时(如 countshowinputValue)。
    • 当你希望代码风格统一,减少 toRefs 的使用(尤其是在 <script setup> 中)。
    • 当你需要替换整个值时(ref.value = newValue)。
  2. 使用 reactive

    • 当你有一个复杂的对象结构,并且希望直接操作其属性时。
    • 当你希望代码在 JavaScript 中看起来更“自然”(无需 .value)。
    • 注意解构问题,必要时配合 toRefs 使用。

推荐实践

  • <script setup> 语法糖中:很多开发者倾向于统一使用 ref,因为它更通用,且在模板中自动解包,JS 中虽然要 .value,但 IDE 通常能很好提示。这可以减少对 toRefs 的依赖。
  • 复杂状态对象:如果有一个包含多个相关属性的大对象,使用 reactive 可能更直观,但记得用 toRefs 解构。
// 推荐:统一使用 ref (尤其在 script setup 中)
const count = ref(0)
const name = ref('')
const userList = ref([])// 或者:复杂对象用 reactive + toRefs
const formState = reactive({name: '',email: '',age: 0
})
const { name, email, age } = toRefs(formState) // 解构后保持响应性

五、总结

  • reactive 是为对象量身定制的响应式解决方案,使用方便但有解构陷阱。
  • ref 是一个通用的响应式容器,通过 .value 包装任何值,是处理基本类型和需要灵活替换场景的首选。
  • 两者可以结合使用,ref 在 reactive 对象中会被自动解包。
  • 选择哪个主要取决于你的数据结构、编码习惯和对解包/解构的偏好。在现代 Vue 开发中,ref 因其通用性而被广泛使用。
http://www.lryc.cn/news/620396.html

相关文章:

  • 云计算-多服务集群部署实战指南:从JumpServer到Kafka、ZooKeeper 集群部署实操流程
  • 命名空间——网络(net)
  • 4.1vue3的setup()
  • EtherCAT概念介绍
  • 防抖 debounce.js
  • Synology File Station 官方 API 指南总结(中文版)
  • windows 资源管理器缩略图 ,支持.MP4(H.265/HEVC编码)视频格式和.HEIC(HEIF)图片格式的软件
  • 《吃透 C++ 类和对象(中):拷贝构造函数与赋值运算符重载深度解析》
  • Cypher注入详解:原理、类型与测试方法
  • Python入门第1课:环境搭建与第一个程序“Hello World”
  • SQL详细语法教程(三)mysql的函数知识
  • Mac 新电脑安装cocoapods报错ruby版本过低
  • 计算机如何进行“卷积”操作:从图像到矩阵的奥秘
  • Java进阶学习之Stream流的基本概念以及使用技巧
  • OS设备UDID查看方法
  • Java毕业设计选题推荐 |基于SpringBoot的健身爱好线上互动与打卡社交平台系统 互动打卡小程序系统
  • UniVoc:基于二维矩阵映射的多语言词汇表系统
  • 机海沉浮录,荣耀的HTC式困局
  • 重塑隐私边界,微算法科技(NASDAQ:MLGO)开发基于边缘计算的轻量级区块链身份隐私保护方案
  • 【论文阅读 | CVPR 2024 | UniRGB-IR:通过适配器调优实现可见光-红外语义任务的统一框架】
  • 【C++】细说继承(2w字详解)
  • 如何手动开启 Hyper-V?Windows 10/11 详细开启教程
  • AI绘画:从算法原理解读其风格、质量与效率变革
  • Python机器学习与深度学习;Transformer模型/注意力机制/目标检测/语义分割/图神经网络/强化学习/生成式模型/自监督学习/物理信息神经网络等
  • 医疗洁净间的“隐形助手”:富唯智能复合机器人如何重塑手术器械供应链
  • postgreSQL在arcmap中创建企业级数据库
  • k8s+isulad 网络问题
  • 从阿尔法狗到生活日常:机器学习如何重塑我们的世界?
  • 【Java 后端】Spring Boot 集成 JPA 全攻略
  • 推荐三个国内开源数据治理工具