ref/reactive 声明变量 有什么区别??
在 Vue 3 中,ref
和 reactive
都是用于声明响应式变量的 API,核心作用是让变量的变化能够被 Vue 追踪,从而触发视图更新。但它们的使用场景和特性有明显区别,具体如下:
1. 处理的数据类型不同
ref
:
用于包装基本数据类型(String、Number、Boolean、Null、Undefined)和引用数据类型(Object、Array)。
本质是创建一个包含.value
属性的响应式对象,通过.value
访问或修改值。示例:
import { ref } from 'vue'// 基本类型
const count = ref(0)
console.log(count.value) // 访问值:0
count.value = 1 // 修改值(必须通过 .value)// 引用类型
const user = ref({ name: '张三' })
console.log(user.value.name) // 访问:'张三'
user.value.name = '李四' // 修改
reactive
:
仅用于包装引用数据类型(Object、Array),不能直接包装基本类型(否则会报警告且失去响应性)。
直接返回一个响应式代理对象,访问/修改时无需.value
。示例:
import { reactive } from 'vue'// 引用类型(对象)
const user = reactive({ name: '张三', age: 20 })
console.log(user.name) // 访问:'张三'(无需 .value)
user.age = 21 // 修改// 引用类型(数组)
const list = reactive([1, 2, 3])
list.push(4) // 修改数组
2. 访问/修改方式不同
ref
:
无论包装什么类型,都必须通过.value
访问或修改值(在<template>
模板中使用时,Vue 会自动解包.value
,可直接写变量名)。模板中使用:
<template><div>{{ count }}</div> <!-- 无需 .value,自动解包 -->
</template>
reactive
:
直接通过对象属性访问/修改,无需.value
,和操作普通对象一样。模板中使用:
<template><div>{{ user.name }}</div> <!-- 直接访问属性 -->
</template>
3. 对引用类型的“响应式深度”不同
ref
:
包装引用类型时,会自动递归将其转为响应式对象(和reactive
一样,是“深度响应式”)。reactive
:
本身就是深度响应式,对象内部的嵌套属性(即使是多层嵌套)也会被追踪。示例(两者都是深度响应式):
// ref 包装对象
const objRef = ref({ a: { b: 1 } })
objRef.value.a.b = 2 // 响应式生效// reactive 包装对象
const objReactive = reactive({ a: { b: 1 } })
objReactive.a.b = 2 // 响应式生效
4. 解构/展开后的响应性表现不同
ref
:
解构后,基本类型的ref
会失去响应性(因为解构出的是.value
的值);但引用类型的ref
解构后,内部属性仍保持响应性(因为本质是reactive
代理)。示例:
const count = ref(0)
const { value: countVal } = count // 解构基本类型的 ref
countVal = 1 // 不会触发响应式(count.value 仍为 0)const user = ref({ name: '张三' })
const { value: userVal } = user
userVal.name = '李四' // 会触发响应式(因为 userVal 是 reactive 代理)
reactive
:
直接解构会丢失响应性(因为解构出的是普通值,不再是代理对象)。如需保持响应性,需用toRefs
或toRef
转换。示例:
import { reactive, toRefs } from 'vue'const user = reactive({ name: '张三', age: 20 })// 直接解构:失去响应性
const { name, age } = user
name = '李四' // 不会触发响应式// 用 toRefs 转换后解构:保持响应性
const { name: nameRef, age: ageRef } = toRefs(user)
nameRef.value = '李四' // 触发响应式(需 .value,因为 toRefs 转为了 ref)
5. 使用场景总结
API | 适合类型 | 核心特点 | 最佳场景 |
| 基本类型、引用类型 | 需通过 | 声明基本类型变量;需要单独导出的引用类型 |
| 引用类型(Object/Array) | 直接访问属性,无需 | 声明复杂对象/数组,且需整体操作其属性时 |
一句话总结
- 基本类型用
ref
,引用类型优先用reactive
(但ref
也能处理)。 - 记住
ref
带.value
,reactive
直接用,解构reactive
时用toRefs
保响应性。