✨Vue【学习笔记】✨ toRefs()与toRef()

124 阅读3分钟

在Vue的官方文档里是这么描述的

toRef():可以基于响应式对象上的一个属性,创建一个对应的 ref。这样创建的 ref 与其源属性保持同步:改变源属性的值将更新 ref 的值,反之亦然。

toRefs(): 将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。每个单独的 ref 都是使用 [toRef()]创建的。

我们通过一个例子来了解怎么使用他们

<template>
    <div>
        <h2>姓名:{{ person.name }}</h2>
        <h2>年龄:{{ person.age }}</h2>
        <button @click="changeName">修改名字</button>
        <button @click="changeAge">修改名字</button>
    </div>
</template>

<script lang="ts" setup>
    import {reactive} from 'vue'
    let person = reactive({
        name:'张三',
        age:18
    })

    function changeName(){
        person.name += 'X'
    }

    function changeAge(){
        person.age += 1
    }
</script>

<style scoped>

</style>

在这个例子中,我们用reactive代理了一个响应式的对象,这样一来nameage都变成响应式的数据了,并且点击对应的按钮会触发changeName函数与changeAge函数来修改他们的值

从person中解构出name与age

<template>
    <div>
        <h2>姓名:{{ name }}</h2>
        <h2>年龄:{{ age }}</h2>
        <button @click="changeName">修改名字</button>
        <button @click="changeAge">修改名字</button>
    </div>
</template>

<script lang="ts" setup>
    import {reactive} from 'vue'
    let person = reactive({
        name:'张三',
        age:18
    })

    let {name,age} = person

    function changeName(){
        name += 'X'
    }

    function changeAge(){
        age += 1
    }
</script>

<style scoped>

</style>

假设此时将person中的name和age解构出来,将函数中的person.nameperson.age改成nameage,并且将{{ person.name }}{{ person.age }}改成了{{ name }}{{ age }},那么此时还能实现之前的点击对应按钮改变name和age的效果吗?答案是不能的

因为此时通过let {name,age} = person解构出来的nameage其实相当于我们let name = person.namelet age = person.age,虽然person.nameperson.age是响应式的,但我们定义的name与age只接收第一次读到person.name与person.age的值,在函数中通过name += 'X'或age += 1时,其实只是在修改我们let出来的name与age的值,而他们并没有被我们代理成响应式的数据,所以在页面上展示时,他们是不会响应式变化的。

所以现在我们面临一个问题,我们从一个响应式的对象中解构出来的name与age他们并不是响应式的数据,那么如何把他们变成响应式的数据呢?

我们可以用toRefs()来帮我们解决这个问题

    import{toRefs} from 'vue'
    let {name,age} = toRefs(person)

此时我们解构出来的name 与 age 便成为响应式的了

image.png 我们在控制台打印出name与age可以看到此时name 与 age 是由ref定义的响应式数据

所以此时在函数中我们要加上.value

    function changeName(){
        name.value += 'X'
    }

    function changeAge(){
        age.value += 1
    }

所以toRefs()在这里的作用是把一个reactive所定义的对象变成一个一个由ref响应式数据所组成的对象 在控制台console.log(toRefs(person));

image.png 由于经过toRefs(person)处理后的person变成了一个一个由ref响应式数据所组成的对象,所以此时我们let {name,age} = toRefs(person)得到的自然是响应式的name与age了

需要注意一个细节

toRefs()将一个响应式对象转换为一个普通对象,这个普通对象的每个属性都是指向源对象相应属性的 ref。

let {name,age} = toRefs(person)中解构出来的name 与 age 是指向源对象相应属性的 ref,所以如果我们去修改name 与 age ,会同时修改person中原有的person.name与person.age

toRef()

既然toRefs()是把person变成了一个一个由ref响应式数据所组成的对象,那么toRef()的作用便是把person中单独的某个属性变成一个由ref代理的响应式数据

在这里我们将person里的age单独拎出来使其依然可以具有响应式的能力

    let Age = toRef(person,'age')
    console.log(Age);

image.png