toRef怎么用

2023/6/27 ref

# 作用

创建一个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>

获取playerage属性,点击按钮添加年龄的值,页面上的数据响应式修改

1

2

但我们的目的并不是实现age++,因为我们可以直接通过player.age ++ 来实现,我们这样展示的目的是获取到了player中的age属性,同时保持了它的响应式,我们之后就可以把他当做变量来传递了

ref类型的数据同样可以使用toRef(),只是ref一般定义的都是基本数据类型,所以我们可以直接用定义的ref()变量来操作

当我们使用toRef时,即使我们传递的第二个参数,如果该对象并没有该属性,toRef() 也会返回一个可用的 ref,这在处理可选 props 的时候格外实用

# toRefs()

toRefstoRef功能一致,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);
};

3

可以看到效果是一样的

从钩子函数中返回响应式对象时,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 之后的更新

可以将值、refsgetters 规范化为 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++;
};

如果修改会报错

4

# 总结

使用toRef()toRefs()的场景

  • 想要拿到响应式对象中属性,同时保持响应式时
  • 想要暴露出去响应式对象,同时保持响应式时
How to love
Lil Wayne