date
Apr 7, 2023 06:18 AM
type
status
slug
summary
tags
category
updated
Oct 24, 2024 12:53 PM
icon
password
前言
经过前面的环境搭建以及项目构建,完成了基础的项目框架,下面学习实现vue3的reactivity。
观察官方如何使用
首先修改
.npmrc
文件我们在vue3-plan上安装vue3
这个时候发现
node_moules
中vue的依赖被展开了放在根目录上,在packages/reactivity/index.html
上引入vue官方的reactivity
。通过上面的实验观察发现通过
reactive
包裹之后的对象,能被监听到变化,然后effect
通过监听到变化而触发回调函数,从而打印出上面到语句。并且reactive
是能深层检测到对象的改变,当你修改了address
里面的num值时也能被监听到变化,这得益于vue3采用到proxy
。shallowRactive
和shallowReadonly
如名字,只能监听到表层,以为深处到属性并未做包装。vue3对比vue2的变化
- 在Vue2的时候采用
defineProperty
来进行数据的劫持,需要对属性进行重写getter
和setter
性能差。
- 当新增属性和删除属性式就无法监听变化,需要通过
$set
、$delete
实现。
- 数组不采用defineProperty来进行劫持(浪费性能,对所有索引进行劫持会造成性能的浪费)需要对数组单独进行处理。
Vue3使用Proxy来实现响应式数据变化,从而解决上述问题。
编写自己的响应式
首先引入的JS文件的html,从官方的引入链接改成引入自己的链接
为功能划分文件
在
reactivity/src/
下新建effect.ts和reactive.ts文件,对应上面html的2个功能。同时在index.ts中抛出这2个函数
这样html中引入编译好的JS文件就能获取这2个函数了。
- 编写reactive功能
上面定义个了proxy代理对象,但是为啥不能如上图编写。看下面的解析
经过上面的修改,初步得到了一个代理对象的方法。此时如果用户在使用上面的代码的时候,他是这么写的
那么实际上这2个应该使用一个对象的,为此我们修改一下上面的代码,增加缓存设置,这里用上了
WeakMap
。弱链接Map,好处在于key为null自动清空对应映射关系,其二是key只能为对象。修改上面的代码为这个时候reactive就有了同一个对象代理多次,返回同一个代理。现在又有个新需求,如果代理再一次被代理,那应该返回代理,而不是代理的代理对象。
那么怎么让判断为true呢,早期的处理方式是,
WeakMap
,正方向存一次,反方向存一次就像
target
-> proxy
proxy
-> target
最新的处理方法是定一个枚举变量。当你你传入的是proxy的时候,可以看一下时候代理过,如果有,那么他一定走到了get方法,并且我们访问了ReactiveFlags.IS_RECEIVE
,那么就表示这个是被代理过的,就直接返回 target。