Vue -- ref & reactive & toRefs & toRef响应式引用

213 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

本文主要记录了响应式原理,以及ref、reactive、toRefs、toRef的用法。

响应式原理

通过 proxy 对数据进行封装,当数据变化时,触发模板内容更新。

ref

  • 作用:接受一个内部值并返回响应式对象;
  • 处理:一般用于处理基础数据类型;
  • 引用:ref需要从Vue中引入才能使用;
  • 使用:通过value属性获取,使用数据时不需要使用value;
 			// 模板中使用时,vue底层自动调用 .value
            template:`<div>{{name}}</div>`,
            setup(){
                //引入ref
                const { ref } = Vue;
                // 响应式引用,proxy 将 '张三' 变成 proxy({ value: '张三'})
                let name = ref('张三');
                // 两秒后修改 name
                setTimeout(() => {
                    // 修改 name 使用 name.value
                    name.value = '李四';
                }, 2000);
                return{ name }
            }

页面渲染成功渲染出 张三

两秒后更新数据,重新渲染出 李四

reactive

  • 作用:接受一个内部值并返回响应式对象;
  • 引用:从Vue中引入才能使用;
  • 处理:一般用于处理非基础数据类型;
  • 解构:数据解构之后的数据不具备响应式;

数据未解构时

			template:`<div>{{obj.name}}</div>`,
            setup(){
                //引入reactive
                const { reactive } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});
                // 两秒后修改 obj.name
                setTimeout(() => {
                    obj.name = '李四';
                }, 2000);
                return{ obj }
            }

页面渲染成功渲染出 张三

两秒后更新数据,重新渲染出 李四

尝试对数据进行解构

		template:`<div>{{name}}</div>`,
            setup(){
                //引入reactive
                const { reactive } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});
                // 两秒后修改 obj.name
                setTimeout(() => {
                    obj.name = '李四';
                }, 2000);
                const { name } = obj;
                return{ name }
            }

页面渲染成功渲染出 张三

两秒后更新数据,页面没有变化

toRefs

  • 作用:使解构后的数据重新获得响应式;
  • 引用:从Vue中引入才能使用;
  • 封装:封装数据中本身不存在某个数据时,会返回不具备响应式的undefined;

toRefs响应式引用

   		template:`<div>{{name}}</div>`,
            setup(){
                //引入reactive
                const { reactive, toRefs } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});
                // 两秒后修改 obj.name
                setTimeout(() => {
                    obj.name = '李四';
                }, 2000);
                // 通过toRefs包装后会变为proxy({name:proxy({value:'name'})})
                const { name } = toRefs(obj);
                return{ name }
            }

页面渲染成功渲染出 张三

两秒后更新数据,重新渲染出 李四

toRefs封装不存在数据

 		template:`<div>{{age}}</div>`,
            setup(){
                //引入reactive
                const { reactive, toRefs } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});
                // 通过toRefs包装后会变为proxy({name:proxy({value:'name'})})
                const { age } = toRefs(obj);
                // 两秒后修改 age.value
                setTimeout(() => {
                    age.value = '18';
                }, 2000);
                return{ age }
            }

控制台报错 在这里插入图片描述

toRef

  • 作用:封装数据中不存在数据时,不会报错,会返回具备响应式的值;
  • 使用:toRef方法不需要解构;
  • 参数:两个参数,一个总数据,一个获取的数据。
 		template:`<div>{{age}}</div>`,
            setup(){
                //引入reactive
                const { reactive, toRef } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});

                const  age  = toRef(obj, 'age');
                // 两秒后修改 age.value
                setTimeout(() => {
                    age.value = '18';
                }, 2000);
                return{ age }
            }

页面两秒后渲染出:18

在这里插入图片描述

readonly

  • 作用:取得一个对象或ref并返回一个只读代理;
  • 引用:从Vue中引入才能使用;
		template:`
            <div>{{obj.name}}</div>
            <div>{{copyObj.name}}</div>
            `,
            setup(){
                //引入reactive
                const { reactive, readonly } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});
                let copyObj = readonly({name: '张三'});
                // 两秒后修改 obj.name
                setTimeout(() => {
                    obj.name = '李四';
                    copyObj.name = '李四';
                }, 2000);
                return{ obj, copyObj }
            }

页面效果 在这里插入图片描述 两秒后页面效果,同时控制台给出警告。 在这里插入图片描述 在这里插入图片描述

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3 -- 响应式引用</title>
    <!-- 使用CDN引入Vue -->
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
    <script>
        const app = Vue.createApp({

            // ref
            // 模板中使用时,vue底层自动调用 .value
            // template:`<div>{{name}}</div>`,
            // setup(){
            //     //引入ref
            //     const { ref } = Vue;
            //     // 响应式引用,proxy 将 '张三' 变成 proxy({ value: '张三'})
            //     let name = ref('张三');
            //     // 两秒后修改 name
            //     setTimeout(() => {
            //         // 修改 name 使用 name.value
            //         name.value = '李四';
            //     }, 2000);
            //     return{ name }
            // }

            // reactive
            // 未解构
            // template:`<div>{{obj.name}}</div>`,
            // setup(){
            //     //引入reactive
            //     const { reactive } = Vue;
            //     // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
            //     let obj = reactive({name: '张三'});
            //     // 两秒后修改 obj.name
            //     setTimeout(() => {
            //         obj.name = '李四';
            //     }, 2000);
            //     return{ obj }
            // }

            // 解构后
            // template:`<div>{{name}}</div>`,
            // setup(){
            //     //引入reactive
            //     const { reactive } = Vue;
            //     // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
            //     let obj = reactive({name: '张三'});
            //     // 两秒后修改 obj.name
            //     setTimeout(() => {
            //         obj.name = '李四';
            //     }, 2000);
            //     const { name } = obj;
            //     return{ name }
            // }

            // // toRefs
            // template:`<div>{{name}}</div>`,
            // setup(){
            //     //引入reactive
            //     const { reactive, toRefs } = Vue;
            //     // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
            //     let obj = reactive({name: '张三'});
            //     // 两秒后修改 obj.name
            //     setTimeout(() => {
            //         obj.name = '李四';
            //     }, 2000);
            //     // 通过toRefs包装后会变为proxy({name:proxy({value:'name'})})
            //     const { name } = toRefs(obj);
            //     return{ name }
            // }

            //toRefs封装不存在数据
            // template:`<div>{{age}}</div>`,
            // setup(){
            //     //引入reactive
            //     const { reactive, toRefs } = Vue;
            //     // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
            //     let obj = reactive({name: '张三'});

            //     const  { age } = toRefs(obj);
            //     // 两秒后修改 age.value
            //     setTimeout(() => {
            //         age.value = '18';
            //     }, 2000);
            //     return{ age }
            // }

            // //toRef
            // template:`<div>{{age}}</div>`,
            // setup(){
            //     //引入reactive
            //     const { reactive, toRef } = Vue;
            //     // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
            //     let obj = reactive({name: '张三'});

            //     const  age  = toRef(obj, 'age');
            //     // 两秒后修改 age.value
            //     setTimeout(() => {
            //         age.value = '18';
            //     }, 2000);
            //     return{ age }
            // }

            // readonly
            template:`
            <div>{{obj.name}}</div>
            <div>{{copyObj.name}}</div>
            `,
            setup(){
                //引入reactive
                const { reactive, readonly } = Vue;
                // 响应式引用,proxy 将 {name: '张三'} 变成 proxy({name: '张三'})
                let obj = reactive({name: '张三'});
                let copyObj = readonly({name: '张三'});
                // 两秒后修改 obj.name
                setTimeout(() => {
                    obj.name = '李四';
                    copyObj.name = '李四';
                }, 2000);
                return{ obj, copyObj }
            }
        });        
        const vm = app.mount('#root');
    </script>
</body>
</html>

总结

ref:==接受一个基础数据类型值并返回响应式对象,通过value属性获取,使用数据时不需要使用value==;

reactive:==接受一个非基础数据类型值并返回响应式对象,数据解构之后的数据不具备响应式==;

toRefs:==使reactive解构后的数据重新获得响应式,封装数据中本身不存在某个数据时,会返回不具备响应式的undefined==;

toRef:==封装数据中不存在数据时,不会报错,会返回具备响应式的值,toRef方法不需要解构==;

readonly:取得一个对象或ref并返回一个只读代理;

本文到此结束

如果大家还有什么其他想法,欢迎在评论区交流!