在 Vue 中,reactive
和 ref
都是创建响应式数据的核心 API,但它们的适用场景有所不同,选择依据主要取决于数据类型和使用习惯:
1. 用 ref
的场景
典型场景:
- 基本类型数据:
const count = ref(0) // 数字
const name = ref('张三') // 字符串
const isVisible = ref(true) // 布尔值
- 需要单独管理的简单状态:
如组件中的开关状态、计数器、加载状态等独立变量:
const loading = ref(false)
const error = ref(null)
const currentTab = ref('home')
- 在模板中直接使用:
模板中无需.value
,Vue 会自动解包,使用更简洁:
<template><div>{{ count }}</div> <!-- 直接使用,无需 .value -->
</template>
- 需要作为响应式数据传递给函数:
由于ref
是一个包装对象,传递时能保持响应性(避免基本类型的 "值传递" 丢失响应性):
function increment(num) {num.value++ // 能正确修改原始 ref 的值
}
increment(count)
2. 用 reactive
的场景
典型场景:
- 多属性的复杂对象:
如用户信息、表单数据等包含多个字段的结构:
const user = reactive({name: '张三',age: 25,address: { city: '北京' } // 支持嵌套对象
})
- 聚合相关状态:
将逻辑关联的状态放在一起,使代码更有条理:
const form = reactive({username: '',password: '',rememberMe: false
})
- 数组或集合类型:
管理列表数据时,reactive
可以直接处理数组的响应式:
const list = reactive([{ id: 1, name: 'item1' },{ id: 2, name: 'item2' }
])
list.push({ id: 3, name: 'item3' }) // 响应式更新
- 避免过多
ref
变量:
当组件状态较多时,用reactive
聚合比声明多个ref
更简洁:
// 优于:const a = ref(1); const b = ref(2); const c = ref(3)
const state = reactive({a: 1,b: 2,c: 3
})
3. 核心区别与选择原则
维度 |
|
|
适用类型 | 基本类型、对象、数组 | 仅对象 / 数组(非基本类型) |
访问方式 | 需要 | 直接访问属性 |
解构特性 | 解构后仍可保持响应性 | 直接解构会丢失响应性 |
替换整个数据 | 可以( | 不可以(会破坏代理) |
选择原则:
- 简单值用
ref
:数字、字符串、布尔等基本类型,或独立的简单状态。 - 复杂对象用
reactive
:多属性对象、数组,或需要聚合管理的相关状态。 - 优先
ref
:如果不确定用哪个,ref
更通用(可处理所有类型),尤其在 Composition API 中更常用。
4. 常见错误与注意事项
- 不要用
reactive
处理基本类型(无效):
const count = reactive(0) // 错误!reactive 对基本类型无效
reactive
对象直接赋值会丢失响应性:
const user = reactive({ name: '张三' })
user = { name: '李四' } // 错误!这样会覆盖代理对象,失去响应性
- 解构
reactive
对象需用toRefs
保持响应性:
import { toRefs } from 'vue'
const { name, age } = toRefs(user) // 解构后仍有响应性