模式切换
响应式工具: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 需要这些工具?
- 直接解构会失去响应性,这些工具能保持连接