在 Vue 3 的 Composition API 中,ref 和 reactive 都是创建响应式数据的方法,但它们有以下主要区别:
1. 数据类型
ref: 可以处理基本类型和对象类型javascript
const count = ref(0) // 基本类型 const obj = ref({ name: 'John' }) // 对象类型reactive: 只能处理对象类型(包括数组、Map、Set等)javascript
const state = reactive({ name: 'John', age: 25 }) // 对象 const arr = reactive([1, 2, 3]) // 数组
2. 访问方式
ref: 需要通过.value访问和修改javascript
const count = ref(0) console.log(count.value) // 访问 count.value++ // 修改reactive: 直接访问属性javascript
const state = reactive({ count: 0 }) console.log(state.count) // 访问 state.count++ // 修改
3. 模板中使用
ref: 在模板中自动解包,无需.valuevue
<template> <div>{{ count }}</div> <!-- 自动解包 --> </template> <script setup> const count = ref(0) </script>reactive: 直接使用属性vue
<template> <div>{{ state.count }}</div> </template>
4. 响应式原理
ref: 内部使用reactive包装对象类型,基本类型通过 getter/setter 实现reactive: 使用 Proxy 实现深度响应式
5. 重新赋值
ref: 可以替换整个值javascript
const obj = ref({ a: 1 }) obj.value = { b: 2 } // 可行reactive: 不能直接替换整个对象(会失去响应性)javascript
let state = reactive({ a: 1 }) state = { b: 2 } // ❌ 失去响应性
6. 使用 toRefs
reactive: 解构时会失去响应性,需要toRefsjavascript
const state = reactive({ x: 1, y: 2 }) const { x, y } = toRefs(state) // 保持响应性ref: 无此问题
7. TypeScript 类型推断
ref: 保持类型typescript
const count = ref<number>(0) // Ref<number>reactive: 会展开类型typescript
const state = reactive({ count: 0 }) // { count: number }
使用建议
使用 ref 当:
处理基本类型(string、number、boolean 等)
需要重新赋值的引用
在组合函数中返回响应式数据
不确定数据类型时
使用 reactive 当:
处理复杂的对象或嵌套结构
需要深度响应式且不需要重新赋值
状态逻辑紧密相关,作为一个整体管理
示例对比
javascript
// 使用 ref
const userRef = ref({
name: 'Alice',
age: 30,
address: {
city: 'Beijing'
}
})
// 使用 reactive
const userReactive = reactive({
name: 'Alice',
age: 30,
address: {
city: 'Beijing'
}
})
// 访问
console.log(userRef.value.name) // 需要 .value
console.log(userReactive.name) // 直接访问
// 修改
userRef.value.age = 31
userReactive.age = 31总结
ref更通用,适合大多数场景reactive适合管理复杂的状态对象在实际项目中,两者经常结合使用,根据具体需求选择