ref、toRef、toRefs 的区别与使用场景
Vue 3 中三种响应式 API 的作用和使用方式
问题
Vue 3 提供了 ref、toRef、toRefs 三个 API,它们分别解决什么问题?为什么需要这三个 API?
解答
为什么需要 ref
reactive 只能处理对象类型,无法处理基本类型(string、number、boolean)。ref 解决了这个问题。
import { ref, reactive } from 'vue'
// reactive 无法处理基本类型
const count = reactive(0) // ❌ 不会响应式
// ref 可以处理任意类型
const count = ref(0) // ✅ 响应式
const user = ref({ name: 'Tom' }) // ✅ 对象也可以
// 访问和修改
console.log(count.value) // 0
count.value++
为什么需要 toRef
从 reactive 对象中解构属性会丢失响应式。toRef 可以为 reactive 对象的某个属性创建一个 ref,保持响应式连接。
import { reactive, toRef } from 'vue'
const state = reactive({
name: 'Tom',
age: 20
})
// 直接解构会丢失响应式
let { age } = state
age++ // ❌ state.age 不会变化
// 使用 toRef 保持响应式
const ageRef = toRef(state, 'age')
ageRef.value++ // ✅ state.age 也会变成 21
// 双向绑定:修改原对象,ref 也会更新
state.age = 30
console.log(ageRef.value) // 30
为什么需要 toRefs
toRefs 是 toRef 的批量版本,将 reactive 对象的所有属性转换为 ref。
import { reactive, toRefs } from 'vue'
const state = reactive({
name: 'Tom',
age: 20,
city: 'Beijing'
})
// 批量转换为 ref
const { name, age, city } = toRefs(state)
// 每个属性都是 ref,且保持响应式连接
age.value++ // state.age 变成 21
state.name = 'Jerry' // name.value 变成 'Jerry'
实际应用:composable 函数
toRefs 最常见的用途是在组合式函数中返回响应式数据:
import { reactive, toRefs } from 'vue'
// 封装一个 composable
function useMouse() {
const state = reactive({
x: 0,
y: 0
})
const update = (e) => {
state.x = e.pageX
state.y = e.pageY
}
window.addEventListener('mousemove', update)
// 返回 toRefs,调用方可以解构使用
return toRefs(state)
}
// 使用时可以解构,且保持响应式
const { x, y } = useMouse()
三者对比
import { ref, reactive, toRef, toRefs } from 'vue'
// ref:创建独立的响应式引用
const count = ref(0)
// reactive:创建响应式对象
const state = reactive({ a: 1, b: 2 })
// toRef:为 reactive 的单个属性创建 ref
const aRef = toRef(state, 'a')
// toRefs:为 reactive 的所有属性创建 ref
const { a, b } = toRefs(state)
关键点
ref用于创建任意类型的响应式数据,通过.value访问reactive对象解构后会丢失响应式toRef为 reactive 的单个属性创建 ref,保持双向绑定toRefs批量转换,常用于 composable 函数的返回值- 三者配合使用,解决不同场景下的响应式需求
目录