Vue 3 常用响应式数据类型详解:ref、reactive、toRef 和 toRefs
Vue 3 常用响应式数据类型详解:ref、reactive、toRef 和 toRefs
1. ref() - 响应式引用
基本概念
ref
是 Vue 3 中最基础的响应式 API,用于创建一个包含响应式数据的引用对象。
核心特点
- 可以包装任何值类型(基本类型、对象、数组等)
- 通过
.value
属性访问和修改值 - 模板中自动解包(不需要写
.value
)
使用示例
import { ref } from 'vue'// 基本类型
const count = ref(0)
console.log(count.value) // 0
count.value++ // 修改值// 对象类型
const user = ref({ name: '张三', age: 25 })
console.log(user.value.name) // '张三'
user.value.age = 26 // 修改嵌套属性// 模板中使用(自动解包)
// <div>{{ count }}</div>
// <div>{{ user.name }}</div>
适用场景
- 基本数据类型(字符串、数字、布尔值等)
- 需要完全替换引用的对象
- 需要明确区分响应式和非响应式数据时
2. reactive() - 响应式对象
基本概念
reactive
用于创建深度响应式的对象(包括数组、Map、Set 等集合类型)。
核心特点
- 返回对象的 Proxy 代理
- 嵌套对象也是响应式的
- 不需要
.value
访问 - 解构或展开会失去响应性
使用示例
import { reactive } from 'vue'const state = reactive({count: 0,user: {name: '李四',age: 30},hobbies: ['阅读', '编程']
})// 直接访问和修改
console.log(state.count) // 0
state.count++// 嵌套对象也是响应式的
state.user.name = '王五'// 数组操作也是响应式的
state.hobbies.push('游泳')
适用场景
- 复杂的对象结构
- 需要深度响应式的场景
- 需要管理多个相关状态时
3. toRef() - 转换为单个 ref
基本概念
toRef
用于从 reactive 对象中提取单个属性并保持响应性连接。
核心特点
- 保持与源属性的响应式连接
- 修改会双向影响源对象
- 即使源属性不存在也会创建 ref
使用示例
import { reactive, toRef } from 'vue'const state = reactive({count: 0,name: '张三'
})// 将响应式对象的属性转为ref
const countRef = toRef(state, 'count')// 修改会双向影响
countRef.value++
console.log(state.count) // 1state.count++
console.log(countRef.value) // 2// 即使属性不存在也会创建ref
const nonExistRef = toRef(state, 'nonExist')
nonExistRef.value = '新值' // 会添加到原对象
console.log(state.nonExist) // '新值'
适用场景
- 需要将 reactive 对象的某个属性单独传递时
- 需要确保属性访问的响应性时
- 组合式函数中返回单个属性时
4. toRefs() - 转换为多个 ref
基本概念
toRefs
将 reactive 对象转换为普通对象,但每个属性都是 ref。
核心特点
- 保持所有属性的响应式连接
- 方便解构而不失去响应性
- 常用于组合式函数返回值
使用示例
import { reactive, toRefs } from 'vue'const state = reactive({count: 0,name: '张三'
})// 转换为ref对象
const stateRefs = toRefs(state)
/*
{count: Ref<number>,name: Ref<string>
}
*/// 解构后仍保持响应性
const { count, name } = toRefs(state)
count.value++
console.log(state.count) // 1// 组合式函数中使用
function useFeature() {const state = reactive({ x: 0, y: 0 })return toRefs(state) // 调用方可以解构而不失去响应性
}const { x, y } = useFeature()
适用场景
- 从组合式函数返回 reactive 对象时
- 需要解构 reactive 对象但保持响应性时
- 需要将 reactive 对象的属性批量传递给子组件时
对比总结
特性 | ref | reactive | toRef | toRefs |
---|---|---|---|---|
创建方式 | ref(value) | reactive(obj) | toRef(obj, key) | toRefs(obj) |
值访问 | 需要 .value | 直接访问 | 需要 .value | 每个属性需要 .value |
模板使用 | 自动解包 | 直接使用 | 自动解包 | 每个属性自动解包 |
主要用途 | 基本类型/对象引用 | 复杂响应式对象 | 提取单个响应式属性 | 解构响应式对象 |
响应性保持 | 完全响应式 | 深度响应式 | 保持与源连接 | 保持所有属性连接 |
最佳实践建议
-
基础选择原则:
- 简单数据用
ref
- 复杂对象用
reactive
- 需要解构用
toRefs
- 简单数据用
-
组合式函数:
- 返回响应式数据时优先使用
toRefs
- 这样调用方可以自由解构
- 返回响应式数据时优先使用
-
性能考虑:
- 大型对象使用
reactive
比多个ref
更高效 - 不需要深度响应式时考虑
shallowRef
/shallowReactive
- 大型对象使用
-
代码组织:
- 相关状态组织在一个
reactive
对象中 - 独立值使用
ref
- 相关状态组织在一个
-
类型安全:
- 为
ref
和reactive
提供 TypeScript 类型注解
const count = ref<number>(0) const state = reactive<{name: string, age: number}>({name: '', age: 0})
- 为
这些响应式 API 是 Vue 3 组合式 API 的核心,理解它们的特性和适用场景对于开发高效的 Vue 应用至关重要。