前言
这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情”
ref是vue3响应式里面非常核心的一个api,与rective相比,在使用ref的过程中,在进行赋值的操作的时候,必须要加上.value,个人并不喜欢这样的书写方式,所以在看官网的过程中发现可以使用$ref的形式来避免这种方式,。
reactive和ref的关系
有的人在开发的过程中直接ref一把梭,然后舍弃reactive,这样确实可以,但是不是很规范,从源码角度来看的话,在ref中传入一个对象的话,那么最后还是要通过reactive的方式去实现相关的源码。
正文
接下来我们来看下ref的底层原理。
包的引入
首先,我们来看下ref源码里面引入的包,可以发现,很多包是从effect的包里面引入的,其中主要包括收集依赖以及触发依赖的相关操作。与此同时,可以发现从reactive里面引入像isReactive和isReadonly等一系列的包来判断是否是reactive以及readonly等。
RefIml类
之后,我们来看核心实现class RefIml。可以看到,这里面有和reactive源码实现比较类似的内容。其中包括get set等操作,get的时候会执行trackRefValue去收集依赖,set的时候会执行triggerRefValue去触发依赖。
hasChanged方法
细看set value(newVal),会发现里面有个hasChanged这个方法,这个用于比较newVal和_rawValue,以此来判断值是否发生了改变。如果发生了改变,则执行触发依赖的操作;反之,则不执行触发依赖的操作。
trackRefValue
如下图所示,我们来看下trackRefValue是如何收集依赖的。首先会判断shouldTrack是否为true以及activeEffect是否存在。在这里面我们可以看到收集依赖还是基于effect里面的trackEffects实现的。
triggerRefValue
接下来我们看triggerRefValue这个方法,如下图所示,我们可以看到这里面也用到了toRaw这个方法,那么这个方法的作用是什么呢,在vue3官方文档里面也有介绍,
toRaw() 可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly()创建的代理对应的原始对象。
在这里面我们可以看到用到了triggerRefValue这个方法来进行触发依赖,这个方法依然源自effect,只不过传入的参数不一样罢了。
最后
到这里,ref的相关使用以及其底层原理就讲完了,如有不足,欢迎大家评论区评论并指正。