模式切换
响应式工具:toRefs、toRef、isRef
Vue 3 提供了一系列响应式工具函数来处理 ref 和 reactive 对象,其中最常用的是 toRefs、toRef 和 isRef。这些工具在组合式 API 开发中至关重要。
toRefs:解构响应式对象
作用
将 reactive 对象转换为普通对象,其中每个属性都是 ref 引用,保持响应性。
为什么需要?
直接解构 reactive 对象会失去响应性:
javascript
const state = reactive({ count: 0, name: 'Alice' })
const { count, name } = state // ❌ 解构后失去响应性正确用法
javascript
import { reactive, toRefs } from 'vue'
const state = reactive({
count: 0,
name: 'Alice'
})
// ✅ 保持响应性
const { count, name } = toRefs(state)
count.value++ // 仍然响应式实现原理
伪代码实现:
javascript
function toRefs(reactiveObj) {
const result = {}
for (const key in reactiveObj) {
result[key] = toRef(reactiveObj, key)
}
return result
}使用场景
- 从组合式函数返回
reactive对象时 - 需要在模板中解构 props 时
- 将
reactive对象的属性传递给需要ref的函数时
toRef:创建属性引用
作用
为 reactive 对象的某个属性创建 ref 引用,保持与源属性的响应式连接。
与 toRefs 的区别
toRefs:转换整个对象的所有属性toRef:只转换单个指定属性
基本用法
javascript
import { reactive, toRef } from 'vue'
const state = reactive({
count: 0,
user: {
name: 'Alice'
}
})
// 创建单个属性的 ref
const countRef = toRef(state, 'count')
const userNameRef = toRef(state.user, 'name')
countRef.value++ // 会更新原 state.count典型场景
- 需要将
reactive的某个属性单独传递时 - 需要保持与源属性的响应式连接时
javascript
// 在组合式函数中使用
function useFeatureX(state) {
const countRef = toRef(state, 'count')
// ...基于 countRef 的逻辑
}isRef:检查引用类型
作用
检查一个值是否是 ref 对象。
基本用法
javascript
import { ref, isRef } from 'vue'
const count = ref(0)
const plain = 42
console.log(isRef(count)) // true
console.log(isRef(plain)) // false实现原理
javascript
function isRef(r) {
return !!(r && r.__v_isRef === true)
}使用场景
- 在工具函数中处理可能是
ref的参数 - 编写通用逻辑时需要区分普通值和响应式引用
javascript
function double(maybeRef) {
return isRef(maybeRef) ? maybeRef.value * 2 : maybeRef * 2
}综合比较
| 工具函数 | 输入 | 输出 | 主要用途 |
|---|---|---|---|
toRefs | reactive 对象 | 普通对象(属性为 ref) | 解构 reactive 对象 |
toRef | reactive 对象 + 属性名 | 单个 ref | 创建单个属性引用 |
isRef | 任意值 | 布尔值 | 检查 ref 类型 |
最佳实践
组合式函数返回:
javascriptfunction useCounter() { const state = reactive({ count: 0 }) return { ...toRefs(state) } // 方便使用者解构 }props 处理:
javascriptconst props = defineProps({ count: Number }) const countRef = toRef(props, 'count') // 保持响应性类型安全(TypeScript):
typescriptinterface State { count: number name: string } const state = reactive<State>({ count: 0, name: 'Alice' }) const { count, name } = toRefs(state) // 保持类型推断
常见问题
Q1:toRefs 和 toRef 会创建新引用吗?
- 不会,它们创建的是对原始属性的代理引用
Q2:什么时候该用 toRef 而不是 toRefs?
- 当只需要
reactive对象的个别属性时
Q3:为什么解构 props 需要这些工具?
- 直接解构会失去响应性,这些工具能保持连接
