vue3中ref和reactive,toRef,toRefs区别和理解

157 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

何时需要用到ref或reactive?

在vue3中提供了组合式API,使用这些api通过与<script setup></script>一起结合使用。回归整正题,当我们使用组合式api时,可以通过ref或者reactive函数来创建响应式变量。

语法以及用法区别

创建响应式变量

ref

<script lang="ts" setup>
    import { ref } from "vue";
    const refV = ref("");
</script>

reactive

<script lang="ts" setup>
    import { reactive } from "vue";
    const refV = reactive([]);
</script>

区别

  1. ref创建的响应式变量通常需要使用.value来访问而reactive不需要。 如
<script lang="ts" setup>
    const refV = ref("refValue");
    const reactiveV = reactive(["reactiveValue"]);
    console.log(refV.value);
    console.log(reactiveV);
</script>

结果

1671530809193.png

  1. ref可以传入基本类型和引用类型而reactive只能传入引用类型,如const refO = ref('')是可以的 但是 const reactiveO = reactive('')是不行的(会失去响应式)

ref的一些特殊情况

  1. 在js代码中引用ref通常是需要需用.value来实现,但有一个例外情况: 当一个响应式对象的属性是一个ref时,访问和修改该属性不需要使用value。如
<script lang="ts" setup>
    const refO = reactive({
      refV: ref(""),
    });
    refO.refV = "newValue";
    console.log(refO.refV); //结果是newValue
</script>

使用ref创建的响应式对象也一样
<script lang="ts" setup>
    const refO = ref({
      refV: ref(""),
    });
    refO.value.refV = "newValue";
    console.log(refO.value.refV); //结果是newValue
</script>
  1. 当 ref 在模板中作为顶层属性被访问时,不需要使用.value,如
<script lang="ts" setup>
    const refV = ref("This is a ref Obj");
</script>

在模板中使用可以直接访问 {{ refV }} 但假如ref不是作为顶级属性被访问时,则需要使用.value,如

<script lang="ts" setup>
    const refV = {
      refA: ref(1),
    };
</script>

在模板中则需要使用{{ refV.refA.value + 1}}

  1. 当ref是模板中的插值表达式的最终值时,不需要使用.value, 如上述例子,假如插值表达式为{{ refV.refA }} 则页面上会返回1

toRef

toRef官方的解释是基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步。其实就是让你能够实现将reactive中的某个属性赋值给另一个变量时,改变该变量,reactive中的属性能够同步改变,反之亦然。想象这样一个场景,当远程服务器给我们返回这样一个json:

const resp = ref({
  name: "JoeZhou",
  ageObj: {
    age: 18,
  },
});

现在我们需要用到该返回中的age属性,并且需要对此属性做一些计算,由于拿取age的数据结构很长(resp.value.ageObj.age),我们想将其提取出来,当我们计算完时,想让resp上的age变成计算后的结果,还需要进行赋值操作,如

let age = resp.value.ageObj.age;
age += 1;
resp.value.ageObj.age = age;

通过toRef我们可以将其简化

const age = toRef(resp.ageObj.age);
age.value += 1;

对age的value赋值之后,resp中的ageObj中的age也会同步新值。

toRefs 其实和toRef的功能相似,它会对传入的对象的每个属性都使用toRef创一个ref,让我们使用解构赋值也不会失去对源数据的同步性。

如上述例子,假设ageObj中不止有age,还有birthday等等的属性,我们可以通过toRefs来实现一次性创建多个ref。

const { age, birthday } = toRefs(resp.value.ageObj);
age.value 进行操作
birthday.value进行操作

总结(总结为自我理解,如有错误请指出)

  1. 当创建是的引用型对象,且在上述不需要书写.value的情况下,使用ref和reactive几乎相同。

  2. ref可以创建基本类型变量而reactive不行

  3. 通过toRef和toRefs实现将reactive中的某个属性赋值给另一个变量时,该变量和源数据“双向绑定”。我们可以借此简化代码。