← 返回首页
Vue3基础教程(二十六)
发表时间:2021-08-12 00:01:23
toRef与toRefs

1.toRef toRef可以把一个响应式对象转换成普通对象,该普通对象的每个 property 都是一个 ref。

我们知道ref可以用于创建一个响应式数据,而toRef也可以创建一个响应式数据,那他们之间有什么区别呢?事实上,如果利用ref函数将某个对象中的属性变成响应式数据,修改响应式数据是不会影响到原始数据。

实例:

<template>
    <h1>toRef</h1>
    <hr>
    <div>
        name:{{name}}<br>
        age:{{age}}<br>
    </div>
    <button @click="change">change</button>
</template>

<script lang="ts">
    import {defineComponent, ref, toRef} from 'vue';

    export default defineComponent({
        name: 'App',
        setup() {
            let obj = {name: 'tom', age: 12};
            let newObj = ref(obj.name);
            function change() {
                newObj.value = 'jerry';
                console.log(obj, newObj)
            }

            return {...obj,newObj, change}
        }
    });
</script>

上述代码,当change执行的时候,响应式数据发生改变,而原始数据obj并不会改变。

{name: "tom", age: 12} RefImpl {_shallow: false, __v_isRef: true, _rawValue: "jerry", _value: "jerry"}

原因在于,ref的本质是拷贝,与原始数据没有引用关系

需要注意ref(obj.name)相当于ref('alice')相当于reactive({value:'alice'}) 所以在修改数据时,是修改newObj.value=xxx

而如果使用toRef将某个对象中的属性变成响应式数据,修改响应式数据是会影响到原始数据的。但是需要注意,如果修改通过toRef创建的响应式数据,并不会触发UI界面的更新。 所以,toRef的本质是引用,与原始数据有关联。

<template>
    <h1>toRef</h1>
    <hr>
    <div>
        name:{{name}}<br>
        age:{{age}}<br>
    </div>
    <button @click="change">change</button>
</template>
<script lang="ts">
    import {defineComponent, ref, toRef} from 'vue';

    export default defineComponent({
        name: 'App',
        setup() {
            let obj = {name: 'tom', age: 12};
            let newObj = toRef(obj, 'name');
            function change() {
                newObj.value = 'jerry';
                console.log(obj, newObj)
            }
            return {...obj,newObj, change}
        }
    });
</script>

上述代码,当change执行的时候,响应式数据发生改变,原始数据obj也会改变,但是UI界面不会更新。

{name: "jerry", age: 12} 

ObjectRefImpl {_object: {…}, _key: "name", __v_isRef: true}
__v_isRef: true
_key: "name"
_object: {name: "jerry", age: 12}
value: (...)
__proto__: Object

实例:

有时候外部函数需要接收一个Ref类型参数,可以使用toRef转换。 App.vue

<template>
    <h2>toRefs</h2>
    <div>num:{{num}}</div>
    <button @click="update">更新num</button>
    <hr>
    <Child :foo="num"></Child>
</template>

<script lang="ts">
    import {defineComponent,reactive, ref} from 'vue'
    import Child from '@/components/Child.vue'
    export default {
        name: 'App',
        components:{
            Child
        },
        setup() {
            const num = ref(1);
            const update =()=>{
                 num.value ++;
            }
            return {
                num,
                update
            }
        }
    }
</script>

Child.vue

<template>
    <h2>Child</h2>
    <h3>num:{{foo}}</h3>
    <h3>length:{{length}}</h3>
</template>

<script lang="ts">
    import { computed, defineComponent, Ref, toRef } from 'vue'
    const component = defineComponent({
        props: {
            foo: {
                type: Number,
                require: true
            }
        },
        setup (props, context) {
            const length = useFeatureX(toRef(props, 'foo'))
            return {
                length
            }
        }
    })
    function useFeatureX(foo: Ref) {
        const lenth = computed(() => foo.value.toString().length)
        return lenth
    }
    export default component
</script>

2.toRefs 有的时候,我们希望将对象的多个属性都变成响应式数据,并且要求响应式数据和原始数据关联,并且更新响应式数据的时候不更新界面,就可以使用toRefs.

toRefs的最主要的应用场景在于当从合成函数返回响应式对象时,这样消费组件就可以在不丢失响应式的情况下对返回的对象进行分解使用。

实例1:

<template>
    <h1>toRef</h1>
    <hr>
    <div>
        name:{{name}}<br>
        age:{{age}}<br>
    </div>
</template>

<script lang="ts">
    import {defineComponent, ref, toRef,reactive,toRefs} from 'vue';
    export default defineComponent({
        name: 'App',
        setup() {
            function useReatureX() {
                const user = reactive({
                    name: 'tom',
                    age: 20,
                })
                setTimeout(() => {
                    user.name = 'jerry'
                    user.age = 17
                }, 2000);
                return toRefs(user)
            }
            const {name, age} = useReatureX()
            return {name,age}
        }
    });
</script>