讲一下Vue3的响应式API(toRef, toRefs)

890 阅读4分钟

前言

Vue3从发布到现在,相信大家已经开始学习&&使用了吧,看到响应性 API -> Refs模块的时候是不是觉得:Wa ,这都是什么,好多API长得还很相似。什么ref , unref, toRef, toRefs, isRef......

本文主要介绍toRef和toRefs的用法以及其他响应性 API的扩展,希望对大家有所帮助。

菜鸡认知,如有错误欢迎指正。

正文

toRef和toRefs都是响应性 API,但是在使用上却有很大的不同,本文将带你一起探索

说他们之前 我们先来看一看这两个API

ref

  • 接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value 属性,指向该内部值。
  • 如果将对象分配为 ref 值,则它将被 reactive 函数处理为深层的响应式对象。
  • 常用于简单数据类型,也可以用于对象。

reactive

  • 当将 ref 分配给 reactive property 时,ref 将被自动解包。
  • reactive 将解包所有深层的 refs,同时维持 ref 的响应性。
  • 响应式转换是“深层”的——它影响所有嵌套属性。
  • 常用于复杂数据类型

toRef和toRefs用法

toRef

可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。

  • 把响应式对象/普通对象的某一个属性变为 Ref 对象
  • 需要传递两个参数,第一个参数是哪个对象,第二个参数是对象里面的属性

请看下方代码:

<script>
import { reactive, toRef } from "vue";
export default {
  setup(props) {
    const state = reactive({
      age: 18,
      name: "zs"
    });
    const ageRef = toRef(state, "age");
    console.log(ageRef.value) // 18
    ageRef.value++
    console.log(ageRef.value) // 19
    console.log(state.age) // 19

    const nameRef = toRef(state, "name");
    const emptyRef = toRef(state, "empty");
    return {
      ageRef,
      nameRef,
      emptyRef,
    };
  },
};
</script>

上方代码将源对象中的age转换为了ref对象ageRef,对ageRef进行修改发现源对象中的age也跟随着修改

toRef只能把某一个属性变化为ref对象

有同学会想到:

“如果对象里面有100个参数 需要变化为ref对象,我要难道要写100次吗?”

这个时候toRefs就派上用场了

toRefs

将响应式对象转换为普通对象,普通对象的每个属性都是 ref对象。

只会为源对象中包含的 属性 生成 ref。如果要为特定的 property 创建 ref,则应当使用 toRef

<script>
import { reactive, toRefs } from "vue";
export default {
  setup(props) {
    const state = reactive({
      age: 18,
      name: "zs"
    });
    const stateToRefs = toRefs(state)
    console.log(stateToRefs.age.value) // 18
    stateToRefs.age.value++
    console.log(stateToRefs.age.value) // 19
    console.log(state.age) // 19
    return {
        ...stateToRefs
    };
  },
};
</script>

可以看出, toRefs大大的减少了代码量,还可以通过解构赋值返回响应式对象,真的是yyds!

小明:“源对象里面如果再包含一个对象他还会是响应式的吗?“

我们将上方的state加一个family的对象,然后对family里面的属性操作看一看会是什么样的情况

<template>
   <div>age---{{ family.age }}</div>
  <button @click="family.age++">年龄+1</button>
</template>
<script>
import { reactive, toRefs } from "vue";
export default {
  setup(props) {
    const state = reactive({
      age: 18,
      name: "zs",
      family:{
        shaikh:'毛里求斯',
        age:188
      }
    });
    const stateToRefs = toRefs(state)
    
    return {
        ...stateToRefs
    };
  },
};
</script>

上方例子看到:包含了对象仍然是响应式,我们再来看看对象里面包含数组的响应式例子 state改造如下

const state reactive({
      age18,
      name"zs",
      family:{
        shaikh:'毛里求斯',
        age:188,
        member:[
          {
            age:2,
            id:'1',
            name:'宝宝'
          },
           {
            id:'2',
            age:55,
            name:'爸爸'
          },
           {
            id:'3',
            age:55,
            name:'妈妈'
          }
        ]
      }
    });

视图层改变如下:

<template>
  <div>酋长的年龄---{{ family.age }}</div>
  <h3>家庭成员</h3>
  <div v-for="item in family.member" :key="item.id">
    宝宝的年龄:{{ item.age }} 
    宝宝的名字:{{ item.name }}
    <button @click="item.age++">{{ item.name }}年龄+1</button>
  </div>
</template>

可以看出依然是可以响应式的 toRefs是引用赋值

拓展(引用赋值)

  • 使用‘=’,他只拷贝数据在内存中的地址,应为基本数据类型是存放在 栈 中所以赋值的时候会重新在内存中创建,而引用类型则只会拷贝地址指针
  • 引用赋值:将一个变量的数据地址,“拷贝”一份,传给另了另一个变量。这两个变量,指向“同一个地址”。大家共享同一份数据。如果其中一个变量的值发生了改变,那么,另一个变量的值也得变。要变一起变。

源响应式对象

上方有个词 源响应式对象,这是什么?有同学会有一些困惑。我个人理解的就是:我们需要操作的ref对象,对哪个对象操作 哪个就是源对象。

小节

toRef

  • 当对象中不存在某个属性时会创建该属性,如果要为特定的 property (属性)创建 ref,则应当使用 toRef
  • 需要传递两个参数,第一个参数是哪个对象,第二个参数是对象里面的属性
  • 把响应式对象/普通对象的某一个属性变为 Ref 对象

toRefs

  • toRefs只会为源对象中存在的属性变为 Ref 对象 。如果要为特定的 property (属性)创建 ref,则应当使用 toRef
  • toRefs是引用赋值
  • 把响应式对象的所有属性变为 Ref 对象,可以在不丢失响应性的情况下对返回的对象进行解构/展开

共同点

  • 都是响应式

拓展

unref

如果参数是一个 ref,则返回.value的值,否则返回参数的值。这是 val = isRef(val) ? val.value : val 的语法糖函数。

const add = ref('+1')
unref(add)   // '+1'
const add = '+1'
unref(add)   // '+1'

isRef

检查值是否为一个 ref 对象。

vue3文档地址

Refs