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

文章目录

前言

上一节我们知道了setup函数的数据不具备响应式,这一节我们来解决这一问题。

响应式引用原理

通过 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 }
            }

控制台报错
Vue3 -- ref & reactive & toRefs & toRef响应式引用

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
Vue3 -- ref & reactive & toRefs & toRef响应式引用

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 }
            }

页面效果
Vue3 -- ref & reactive & toRefs & toRef响应式引用
两秒后页面效果,同时控制台给出警告。
Vue3 -- ref & reactive & toRefs & toRef响应式引用
Vue3 -- ref & reactive & toRefs & toRef响应式引用

完整代码

<!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

  • 作用:接受一个基础数据类型值并返回响应式对象
  • 引用:ref需要从Vue中引入才能使用;
  • 使用:通过value属性获取,使用数据时不需要使用value

reactive

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

toRefs

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

toRef

  • 作用:封装数据中不存在数据时,不会报错,会返回具备响应式的值
  • 使用:toRef方法不需要解构
  • 参数:两个参数,一个总数据,一个获取的数据。

readonly

  • 作用:取得一个对象或ref并返回一个只读代理;
  • 引用:从Vue中引入才能使用;

结语

本小节到此结束,谢谢大家的观看!

如有问题欢迎各位指正

上一篇:vue3.0源码核心--reactivity核心模块reactive


下一篇:reactive ref toref torefs 的区别和使用