自从专注于React之后,已经有段时间没有用过Vue了,因此最近在学习Vue3.0,Vue的更新机制与React的更新机制是不同的,React的更新机制说的简单点就是根据场景调用不同方法触发状态更新,从而再次进行渲染,而对于Vue的话,我认为是在发生的数据更新时,根据情况进行渲染的。说的专业点就是Vue拥有一个响应式系统,可以让它在数据更新的时候自动进行视图的更新。在Vue3.0中,可以使用reactive声明响应式状态 ,官方例子:

import { reactive } from 'vue'// 响应式状态
const state = reactive({count: 0
})

也可以创建独立的响应式值:

import { reactive } from 'vue'// 响应式状态
import { ref } from 'vue'const count = ref(0)

那么本文重点来了,在学习到reactive方法的时候,看到文档说不要解构reactive创建的响应式对象,为什么?,因为会失去响应式的功能,那为什么会失去,因为…(并没有解释),而且在观看一个尤大讲解Vue3的视频中,尤大也说了不要解构reactive创建的响应式对象,为什么?,因为会失去响应式的功能,那为什么会失去,因为…(并没有解释)。这个问题隔了几天直到我调试Vue3.0的reactivity之后,我才有了一丝想法,可以简单的看看在调用reactivity方法之后发生了什么:
①先有个例子:

 <div id="app"><p @click="change">{{refCount}}{{count}}</p></div>
     //js代码const { reactive, toRefs } = Vue;const vm = Vue.createApp({setup(props) {//创建响应式对象const rObj = reactive({count: 0});//创建点击事件const change = () => {console.log(rObj.count)rObj.count++;}//利用ref保留与源对象的响应式关联const { count:refCount } = toRefs(rObj);const { count } = rObj;return {//具有响应式refCount,//响应式丢失count,change}}}).mount('#app');

可以看出当点击元素的时候,refCount是随着进行变化的,而count是解构出来的,而它并没有随着变化的。那么调试进入reactive方法:

可以看到它在内部调用了createReactiveObject方法,这名字很好理解就是创建响应式对象,调试进去:

它在这里做了一些处理,细节暂时不探究,重点在这:

创建了一个代理对象将其保存在内部并返回,学习Vue3或多或少都听过Vue3如何进行数据视图更新的,Proxy对数据进行了拦截,当数据发生变化,通知Vue进行视图变化,在new Proxy的第二个参数,它通常使用的baseHanderls:

  const baseHandlers = {get(target, key, receiver) {},set(target, key, value, receiver) {},deleteProxy: (target, key) {},has: (target, key) {},ownKey: (target) {}};

绕了这么久可以看出reactive方法其实就是创建了一个Proxy对象,以及进行了一系列处理,其中并没有找到它可能会失去响应式的情况,也就是说它失去响应式不在于Vue而是在于Proxy对象本身,那么可以简化一下:

     const obj = {count: 1};const proxy = new Proxy(obj, {get(target, key, receiver) {console.log("这里是get");return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {console.log("这里是set");return Reflect.set(target, key, value, receiver);}});

打印出来的效果:

这时想一下如何会因为解构而失去响应式(在这里就当作是打印文字),先试试直接赋值会打印啥:

 proxy.count = 2;

是因为解构相当于重新赋值给另一个变量的原因吗,也就是说它变成了一个新值:

     let {count} = proxy;count = 2;

这里会打印什么,因为失去响应,所以它只打印出来:

好像是这样的感觉,那试试对象:

      const obj = {a: {count: 1}};function reactive(obj) {return new Proxy(obj, {get(target, key, receiver) {console.log("这里是get");if (typeof target[key] === "object") {return reactive(target[key]);};return Reflect.get(target, key, receiver);},set(target, key, value, receiver) {console.log("这里是set");return Reflect.set(target, key, value, receiver);}});};const proxy = reactive(obj);

直接赋值:

         proxy.a.count = 2;console.log(proxy);

先只解构一次看看

     let { a } = proxy;a.count = 3;console.log(proxy);


解构到底

     let { a } = proxy;let { count } = a;count = 3;console.log(proxy);


为什么会不同,其实很好理解,只解构一次,其实新的对象的count仍然是被代理的,

而解构两次,直接获取了count,相当于绕过了代理a。
那么就很好理解了,解构为什么会失去响应,用这个图就可以解释:

因为解构赋值相当于直接跳过了代理那一层,在下面直接获取值,所以get和set无法被调用。

reactive创建的响应式对象解构后为什么会失去响应式相关推荐

  1. js 对象解构_JS对象:解构

    js 对象解构 JS对象:TL; DR (JS Objects: TL;DR) JavaScript has been plagued since the beginning with misunde ...

  2. ES6-4/5 解构赋值、函数默认值、数组解构、对象解构

    ES-4 解构赋值.函数默认值.数组解构.对象解构 ES-5 隐式转换.函数参数解构.解构本质.()用法 一 解构赋值 1 虚值 含义:在Boolean转换结果为假的值falsy 2 函数默认值 ES ...

  3. TypeScript基础-数组结构和对象解构

    解构数组 Typescript 数组解构和JavaScript类似 let input = [1, 2]; let [first, second, three] = input; console.lo ...

  4. ES6基础2(块级作用域、数组对象解构)-学习笔记

    文章目录 ES6基础2(块级作用域.数组对象解构)-学习笔记 块级作用域 数组解构 对象解构 字符串解构 函数的参数解构 ES6基础2(块级作用域.数组对象解构)-学习笔记 块级作用域 //let c ...

  5. ES6/06/ES6简介,ES6新增语法,let声明变量,const声明常量,var,let和const总结,数组解构,对象解构,箭头函数,剩余参数

    ES6简介 ES全称:ECMAScript ; 由ECMA国际化组织制定的标准脚本语言的标准化规范: 为什么使用ES6? 每一次标准的诞生都意味着语言的完善,功能的加强,JavaScript语言本身也 ...

  6. JS解构赋值:数组解构和对象解构

    一种为变量赋值的新语法,一次可以为多个变量赋值. 分成两种情况: 数组解构 let [变量的集合] = [正常的数组] 举例说明: let [x, y, z] = [10, 16, 21]; 上述代码 ...

  7. ES6中的对象解构赋值

    解构赋值: 解构赋值语法是一个Javascript表达式,这使得可以将数据从数组或对象提取到不同的变量中(这段话是mdn中关于解构赋值的定义,注意这里的定义,可以看出解构主要用在数组和对象上). 说白 ...

  8. JavaScript对象解构

    JS对象解构 1. 什么是对象解构 ? 2. 基础使用 2.1) 变量在解构表达式中声明 变量直接使用属性的名称 变量使用自定义名称 2.2) 变量在解构表达式前声明 3. 嵌套解构 4. 函数参数列 ...

  9. 解构里面再次解构_解构后的咖啡:焙炒,研磨和分层,以获得更浓的意式浓缩咖啡

    解构里面再次解构 Over a year ago, I developed a technique called staccato espresso where I used a sifter to ...

最新文章

  1. ui设计怎样做出有效果的视觉层级?
  2. HTML5 Dashboard – 那些让你激动的 Web 技术
  3. nagios插件之登陆防火墙实现session监控
  4. 树莓派wifi环境下初始化及环境配置
  5. pat德才论(java)
  6. iOS之深入解析Block的底层原理
  7. 前端学习(1355)模板语法循环
  8. SharePoint要在master page中动态显示List数据的几种方式
  9. ajax delete 传递参数,springMVC使用PUT、DELETE方法传递参数解决方案
  10. 【BZOJ1188】分裂游戏,博弈
  11. python路径设置方法,R不转义,以及r转义出错SyntaxError
  12. 东北大学材料成型机械设备课后作业答案汇总
  13. PC电脑控制手机iphone(iOS 11、iOS 12、iOS 13),需越狱
  14. arcgis符号库匹配不对的原因_ArcGIS符号库自动匹配方法
  15. 三国志·魏书·田豫传
  16. Android UpdateApk 增量更新
  17. 好消息!想入深户的伙伴们赶紧看过来!
  18. html实现凹陷效果,css3怎么实现字体凹陷凸出效果?(附代码)
  19. 【购房必备知识】成都公积金贷款/商业贷款的一些知识记录
  20. 【Python 教程】11_基础数据类型

热门文章

  1. 深入浅出Linux操作系统搭建JavaEE环境(五)
  2. 我的世界联机教程java_我的世界(minecraft)联机教程
  3. 4、Linux:如何在zip压缩文件中搜索指定内容
  4. html5引入的新标签canvas,HTML页面中添加Canvas标签示例
  5. 前端学习之CSS第三天
  6. go如何实现可选参数
  7. python的third party llibs
  8. vue项目接入高德地图点击地图获取经纬度及省市区
  9. HTML/CSS常见面试题
  10. 应试教育堵死了孩子们犯错的道路