课程地址:【已完结】全网最详细Vue3源码解析!(一行行带你手写Vue3源码)
第二部分-实现响应式(3):(对应课程的第10-14节)
第10节:《定义收集依赖的effect方法》
vue3中的effect相当于vue2中的watcher。
一、在源码中使用effect方法
1、首先,在源码的vue/examples下,新建2.effect.html文件,在其中使用effect方法:
总结:effect函数的作用:它是一个会默认自动执行的方法,当在视图中获取数据时,会触发代理对象的get,此时会进行收集effect;当修改数据时,会触发响应式对象的set,此时执行对应的effect。
effect方法的第二个参数可以传递一个配置对象,当配置lazy:true时,effect不会默认执行:
二、实现effect方法
2、在reactivity下新建effect.ts文件,在其中暴露effect方法:
3、在入口文件中引入并暴露effect方法:
4、编写effect方法:它接收一个函数fn,以及一个配置对象options。其函数体内定义一个函数并返回,且判断options的lazy属性不为真时,该函数会被执行。该函数是由一个createReactiveEffect函数生成的,这个函数接收了外层函数的入参fn和options作为自己的入参:
createReactiveEffect函数内部逻辑为:返回一个方法,并将其保存在effect变量中;这个方法会执行用户传递给effect的方法,即fn入参:
5、测试刚刚编写的effect方法:examples下新建文件2.effect.html
浏览器打开2.effect.html,可以看到控制台打印了500
第11节:《定义栈结构》
1、为effect添加属性:
为什么要为effect添加属性?因为收集effect的目的是为了更新视图,当读取响应式对象的属性A和属性B时,这两个属性分别对应各自的一个effect,它们对应的各自的effect是不一样的,所以需要区别。
2、在createGetter中,获取数据时,添加收集effect逻辑:
3、新建operations操作符文件,在其中定义操作符:
4、引入操作符文件,并在get中读取数据时进行收集effect时,调用Track方法,入参分别为:target(目标对象)、操作符类型,此处为get,key(读取的对象的属性)
5、在effect.ts中定义Track方法。在全局定义activeEffect,保存effect,并传递到Track方法里:
6、打印结果如下:
7、解决一个嵌套的问题,如下代码,effect方法里,又嵌套了一个effect方法,用一个栈形结构来处理这个问题:
第12节:《收集effect依赖》
1、当某个属性被重复读取时,如state.a,此时收集的仍然是其对应的那一个effect,不需要重复收集:
增加 if 判断:
2、在Track方法中收集effect:定义一个WeakMap结构,保存到 targetMap 变量中,首先判断 targetMap 中之中是否已经保存过了 target 这个值,如果没有则将其保存进去,将target(即用户传给响应式API的目标对象)设置为键,new 一个Map结构设置为其对应的值。
在 effect 中读取响应式对象的属性name时:
查看控制台打印出来的 targetMap :
可以看到其结构为:首先它是一个 weakMap 结构,其键为target对象,值为一个Map结构,这个Map结构中,键是被访问的target的属性name,值是一个Set结构,这个Set结构中,存放着effect方法
当在 effect 中使用 name 和 age 时:
分别在两个effect中使用name时:
第13节:《判断数组是否新增还是修改》
vue3与vue2实现响应式还有一个不同的点是:vue3用proxy实现响应式可以直接实现对数组的代理,不需要像vue2一样劫持数组的方法去进行改写
1、在shared中增加几个公共方法:
2、baseHandlers中引入这些公共方法,并在 createSetter 方法中添加如下逻辑:首先存储旧值;然后判断目标对象是数组还是对象,如果是数组且其访问的key值小于数组长度,即读取的数组已有项;如是对象则判断对象是否有被访问的这个属性key,如有则是访问对象的一个已有值。这样就可以区分是为目标对象新增一个key值还是访问目标对象的已有值。
第14节:《总结知识点及面试题》
本节课基本没啥知识点