# 作用
创建一个ref
对象 —— RefImpl()
,其value
值指向另一个对象的某个属性(深拷贝的效果)
获取对象中某个属性 —— 同时保持该属性是响应式的
toRef(param1, param2)
- 第一个参数 —— 你想操作哪个对象
- 第二个参数 —— 你想要对象中的哪个属性
# 使用
toRef()
适用于我们想要拿到这个响应式对象中的某个属性时
不是要对属性进行操作(对属性操作我们可以直接调用定义的reactive
或者ref
原始变量),而是要用一个变量来接收它时,同时保持响应式,我们可以使用该变量,同时保持数据的响应式
<template>
<div>
<h1>{{ player.name }} 的年龄是: {{ player.age }}</h1>
<button @click="add">添加</button>
</div>
</template>
<script setup>
import { reactive, toRef } from "vue";
const player = reactive({
name: "smeb",
age: 26,
});
var age = toRef(player, "age");
console.log(age);
const add = function () {
age.value++;
console.log("age: ", age);
};
</script>
获取player
的age
属性,点击按钮添加年龄的值,页面上的数据响应式修改
但我们的目的并不是实现age++
,因为我们可以直接通过player.age ++
来实现,我们这样展示的目的是获取到了player
中的age
属性,同时保持了它的响应式,我们之后就可以把他当做变量来传递了
ref
类型的数据同样可以使用toRef()
,只是ref
一般定义的都是基本数据类型,所以我们可以直接用定义的ref()
变量来操作
当我们使用toRef
时,即使我们传递的第二个参数,如果该对象并没有该属性,toRef()
也会返回一个可用的 ref
,这在处理可选 props
的时候格外实用
# toRefs()
toRefs
与toRef
功能一致,toRefs()
是将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref
。每个单独的 ref
都是使用 toRef() 创建的
用法: toRefs(obj)
将obj
对象中的所有属性都以RefImpl()
类型给创建出来,所以我们要通过...
运算符来接收这些属性
import { reactive, toRef } from "vue";
const player = reactive({
name: "smeb",
age: 26,
});
var newPlayer = toRefs(player);
console.log(age);
const add = function () {
newPlayer.age.value++;
console.log("age: ", age);
console.log("play.age: ", player.age);
};
可以看到效果是一样的
当从钩子函数中返回响应式对象时,toRefs
是很有用的 —— 组件在调用钩子时可以解构/展开返回的对象而不会失去响应性
// xxx.js
function useFeatureX() {
const state = reactive({
foo: 1,
bar: 2,
});
// ...基于状态的操作逻辑
// 在返回时都转为 ref
return toRefs(state);
}
// xxx.vue
// 可以解构而不会失去响应性
const { foo, bar } = useFeatureX();
toRefs
在调用时只会为源对象上已有的、可枚举的属性创建 ref
。如果要为可能还不存在的属性创建 ref
,要用 toRef
# vue3.3 之后的更新
可以将值、refs
或 getters
规范化为 refs
function toRef<T>(
value: T
): T extends () => infer R
? Readonly<Ref<R>>
: T extends Ref
? T
: Ref<UnwrapRef<T>>
新的用法就是你可以传一个回调函数进去
import { toRef } from "vue";
const props = defineProps(["foo"]);
// 将 `props.foo` 转换为 ref,然后传入
// getter 语法
useSomeFeature(toRef(() => props.foo));
而且这里拿到的数据我们是只能读取(getter
,没有setter
)的,因为他的设计思路就是防止我们对props
进行自行修改
var age = toRef(() => {
return player.age;
});
const add = function () {
age.value++;
};
如果修改会报错
# 总结
使用toRef()
和toRefs()
的场景
- 想要拿到响应式对象中属性,同时保持响应式时
- 想要暴露出去响应式对象,同时保持响应式时