前言:Vue3 中引入了proxy进行数据劫持,而effect是响应式系统的核心,而响应式系统又是 vue3 中的核心,所以vue3的解读要从 effect 开始讲起。

1.reactivity和effect的使用

目前vue3的各个模块都可以单独安装,首先我们需要安装npm i @vue/reactivity,从中引入我们需要的方法,下面是我简单写一段测试代码。

const { reactive, effect } = require("@vue/reactivity");
let a = reactive({value: 1,
});
let b;
effect(() => {b = a.value + 10;console.log(b);
});
a.value = 10;

先别急着看我的输出,想想自己心中的答案是什么?

下面公布控制台的实际输出:

总结:我们会发现effect函数执行了两次,一次是我们往effect函数传入匿名函数时,它立即执行了一次;接下来是我们对响应式变量a.value进行重新赋值时(或者说effect内函数所依赖的响应式变量发生变化时)它又执行了一次。

接下来我们就好好思考下,如何设计一个reactive方法,将传入的值变成响应式,以及实现一个effect函数,其内函数所依赖的响应式数据变化时,该函数会再次执行。

2.Dep和effect的实现

reactive会将传入的变量变成响应式数据,包括对象等数据;地基需要从下往上一层一层的搭建,我们这里先实现将单一变量编译成响应式数据,并用effct对其监听。废话不多说,上代码:

第一步:

class Dep {constructor(val) {this._val = val;}get value() {return this._val;}set value(newVal) {this._val = newVal}
}
const dep = new Dep(10);
console.log('取值:', dep.value);
dep.value = 20;
console.log('赋值:', dep.value);

我们通过class类去创建一个简单的变量,用其构造器constructor初始化对象属性,使用settergetter存取器拦截该属性的存取行为。此时dep就是响应式数据吗?想啥呢!但我们会很熟悉后面的取存值行为,这不就是我们在vue3中使用ref声明变量时,取值和赋值的写法吗!

有了这一步的铺垫,我们接下来的思路是不是更清晰了,只需要在初始化一个Dep时,收集依赖该dep的函数,并在dep值发生变化时,再次执行这个依赖函数,是不是就能实现前面reactiveeffect所达到的效果。ready go

第二步:

let currentEffect;
class Dep {constructor(val) {this.effects = new Set(); // 储存依赖当前变量的函数,并去重this._val = val;}get value() {this.depend();return this._val;}set value(newVal) {this._val = newValthis.notice(); // 赋值时触发依赖}// 收集依赖depend() {if(currentEffect) { // 要记得判空this.effects.add(currentEffect);}}// 触发依赖notice() {this.effects.forEach(effect => {effect();});}
}
const effectWatch = (effect) => {currentEffect = effect;effect(); // 别忘了首先就会执行一次currentEffect = null;
}const dep = new Dep(10);
let b;
effectWatch(() => {b = dep.value + 10;console.log('effectWatch', b);
});
dep.value = 20;

为了讲解时方便区分,所以我在实现effect时,重新取名叫effectWatch;不墨迹了,赶紧看代码,相对于第一步,Dep类新增了两个方法,分别是储存依赖的函数和触发依赖的函数。首先effectWatch在调用时就会执行一次依赖函数,并且是在effectWatch的参数中取dep.value值时,就会将当前依赖函数储存,当我们对dep.value赋值时,会再次触发依赖的函数。

到此为止我们只是实现了一个简化单一的‘reactive’effect,真正的reacive可不仅仅只是传一个普通字符的功能,一起想想下一步该怎么做呢?

3.reactive实现

前面我们已经实现了简单地Dep,它只是一个单一的变量,远远不能满足我们的开发需求。如果我们通过嵌套调用Dep,是不是就能实现reactive的功能了?而且开局我们已经了解到需要使用到proxy对数据进行劫持,那么是不是就好实现多了。

第一步

const reactive = (raw) => {return new Proxy(raw, {get(target, key) {console.log('get----', target[key]);return Reflect.get(target, key);},set(target, key, value) {console.log('set----', key, value);return Reflect.set(target, key, value);}});
}
const user = reactive({name: '春赏百花冬观雪',
});
user.name;
user.age = 24;
user.age;

我们先科普下proxy,就作者而言,很早就学习过该方法,但对于它的应用确实少的可怜(唯唯诺诺的小菜鸡)。proxy就是在我们访问对象前添加了一层拦截,从而实现基本操作的拦截和自定义(我理解为过滤),而且proxy常常与Reflect成对出现,Reflect也就是反射,它的出现简化了我们调用_Object对象_的代码,保持JS的简单,它们之间的基情还需要读者自行去了解哦。

对于user我们可以理解为一个较为复杂的对象,此时的它的每一个属性key所对应的值是不是相当于我前面的dep呢,那么我们只需要再访问该key值时将它通过Dep初始化,从而使整个user的任意属性值发生变化,那么所依赖的函数也能再次执行了,整个user也就成了响应式对象了。从代码来看,第一步依旧是 利用存取器对该user对象进行监听。

第二步

const targetMap = new Map(); // 用于搜集经过reactive初始化的变量
const getDep = (target, key) => {let depsMap = targetMap.get(target); // 从targetMap取,如果有的话if (!depsMap) { // 没有就先储存depsMap = new Map();targetMap.set(target, depsMap);}let dep = depsMap.get(key); // 并将dep与target的key建立连接if (!dep) {dep = new Dep();depsMap.set(key, dep);}return dep;
};
const reactive = (raw) => {return new Proxy(raw, {get(target, key) {const dep = getDep(target, key);dep.depend(); // 当我们访问对象每个属性时,都会收集依赖return Reflect.get(target, key);},set(target, key, value) {const dep = getDep(target, key);const result = Reflect.set(target, key, value); // 重新设置值之后dep.notice(); // 触发依赖return result; // 再return}});
};
const user = reactive({name: '春赏百花冬观雪',
});
effectWatch(() => {user.name;console.log('effect---', user.name);
});
user.name = '晓看天色暮观云';

这里要注意为什么接收Reflect.set后再return抛出,因为我们需要将user.name的值更新后,紧接着触发我们收集到的依赖,最后才能抛出以完成set

作者也是前端小白一枚,只是通过自己的学习并记录以方便自己的回顾,也希望读者大佬们能提出宝贵意见,共同进步。

vue3解读—reactivity响应式实现相关推荐

  1. vue3之实现响应式数据ref和reactive

    用途 ref.reactive都是vue3提供实现响应式数据的方法 ref() 接受一个内部值,返回一个响应式的.可更改的ref对象,此对象只有一个指向其内部的属性.value ref可以说是简化版的 ...

  2. 【Vue3中的响应式原理】

    Vue3响应式原理 在Vue2的响应式中,存在着新增属性,删除属性以及直接通过下标修改数组,但页面不会自动更新的问题.但是在Vue3中,这些问题都得以解决. Vue2中的响应式原理 首先我们先看一下V ...

  3. vue3.0初体验(例子解读reactive响应式)

    目录 准备 vue3 reactive原理例子重点讲解 vue3 reactive原理例子完整代码 准备: 下载vue-next 安装依赖 npm install 核心部分package,里面的vue ...

  4. Vue源码--解读vue响应式原理

    原文链接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方说明里有深入响应式原理这一节.在此官方也提到过: 当你把一个普通的 ...

  5. Vue3通透教程【五】Vue3中的响应式数据 reactive函数、ref函数

    文章目录

  6. Vue3.0源码解读 - 响应式系统

    一.目标对象标识 ** 类似于渲染系统,vue3.0的响应式系统也有自己的一套flag,用于标记目标对象target(通常是我们传入的数据源)的一些特性 export const enum React ...

  7. vue3.0 Beta发布,顺便来看看Vue3 的响应式和以前有什么区别

    前言 vue 3.0 Beta 测试版发布 可以通过vue-cli-plugin-vue-next创建一个vue3.0的beta项目. 目前尚不支持IE11,后期可能会处理兼容版本. 对vue3源码有 ...

  8. 彻底理解Vue数据响应式原理

    彻底理解Vue数据响应式原理 当创建了一个实例后,通过将数据传入实例的data属性中,会将数据进行劫持,实现响应式,也就是说当这些数据发生变化时,对应的视图也会发生改变. const data = { ...

  9. react全局状态管理_rxv: 在React中用Vue3的reactivity包实现状态管理。

    前言 React的状态管理是一个缤纷繁杂的大世界,光我知道的就不下数十种,其中有最出名immutable阵营的redux,有mutable阵营的mobx,react-easy-state,在hooks ...

最新文章

  1. vs2010发布、打包安装程序(超全超详细)
  2. 高校邦python程序设计基础篇_高校邦Python程序设计基础【实境编程】章节答案
  3. Greenplum5单机部署连接报错 System was started in master-only utility mode问题修复
  4. 一元三次方程求解(信息学奥赛一本通-T1238)
  5. 信息学奥赛C++语言: 判决素数个数
  6. 多iframe下的html同名id,获得同级iframe页面的指定ID元素的几种实现方法
  7. java 蓝桥杯 算法训练 区间k大数查询(题解)
  8. listview-android:打造万能通用适配器(转)
  9. Node-ipc 热门包作者投毒“社死‘’,谁来保护开源软件供应链安全?
  10. mongodb 启动 WARNING: soft rlimits too low, transparent_hugepage/enabled is 'always'. never
  11. seaborn无法下载数据的问题
  12. python调用通达信函数_Funcat 将同花顺、通达信等的公式写法移植到了 Python 中
  13. Spire.Doc for Java-根据表格模板生成word表格
  14. 高德导航过程中实时获取道路信息
  15. 关于XD卡写保护问题!
  16. Unity资源处理机制(Assets/WWW/AssetBundle/...)读取和加载资源方式详解
  17. 中美跨境电商贸易投资云洽会成功举办;TT Shop和TTforBusiness将互通;PhonePe月破20亿...|洞悉跨境
  18. 固网服务器win7系统驱动,固网HU-1608n驱动
  19. 使用VNC远程连接云服务器,连接超时问题
  20. 大数据在金融领域主要面临哪些风险,应该怎么解决?

热门文章

  1. 大二女生web开发成长之路——讲述我从软妹子到女汉子的进阶过程
  2. 基于规则的中文地名识别系统的设计与实现
  3. 云闪付怎么对接三方php,第三方支付-银联云闪付开发教程
  4. 【随手记】fatal: cannot do a partial commit during a merge. 解决
  5. Redis基础(二)—— 基本命令与数据类型
  6. python 安卓模拟器 抓包_python + 爬虫 + fiddler + 夜神模拟器 爬取app(1)
  7. 华为云CDN的初次实践总结
  8. 解决Android 模拟机开机黑屏问题、npm内存溢出问题
  9. RTX4060参数 RTX4060功耗 RTX4060 显卡性能
  10. redis中使用lua脚本