目录背景我的心路历程意识到嵌入到现有项目中的风险并试用modules被拆分到packages目录下的不同子目录:可以看出,相对于源码组织从Vue.js2.x开始,monorepo将这些模块拆分成不同的包,每个包都有自己的API和类型定义和测试。这样使得模块拆分的更加细化,职责划分更加清晰,模块之间的依赖关系更加清晰。开发者也更容易阅读、理解和更改所有模块的源代码,提高代码的可维护性。其他一些包(比如reactivity响应式库)可以独立于Vue.js使用,这样如果用户只想使用Vue.js3.0的响应式能力,可以单独依赖这个响应式库,而不是依赖于整个Vue.js,它减少了引用包的大小,但是Vue.js2.x不能这样做。2.我的心路历程这个说起来其实有点好笑,当我有了这个想法,实现了这个东西,甚至在我们组里吹嘘的时候,我就是这样的。不过在知乎和掘金上发现已经有人玩过了。我以为我发现了新大陆,结果是玩剩下的,只有我还蒙在鼓里。然后我就这样了。3.import{effect,reactive}from'@vue/reactivity';import{useRef,useEffect,useMemo,useState}from'react';//当letinitUpdate=false时阻止初始化;constuseReactive=(initState:any)=>{//使用一个状态,这个状态本身没什么用,只是为了强制更新const[,forceUpdate]=useState(0);//保存响应对象(useRef一直保存的原始对象,防止丢失响应对象)constreactiveState=useRef(initState);//缓存响应对象conststate=useMemo(()=>reactive(reactiveState.current),[reactiveState.current]);//监听反应对象变化useEffect(()=>{effect(()=>{for(constiinstate){//访问触发依赖集合state[i];}//强制更新,使用之前无用的状态如果(initUpdate){forceUpdate((num)=>num+1);}如果(!initUpdate)initUpdate=true;});},[state]);returnstate;};exportdefaultuseReactive;在此处测试源代码。实现很简单,这里介绍几个核心要注意的点。核心一:reactive接收一个普通对象,然后返回普通对象的响应式代理。相当于2.x的Vue.observable()。响应式转换是“深度”的:它们影响对象内的所有嵌套属性。基于ES2015的代理实现,返回的代理对象不等于原对象。建议只使用代理对象,避免依赖原始对象。核心2:effect作为reactive的核心,主要负责收集和更新依赖。核心3:触发依赖收集for(constiinstate){//访问触发依赖收集state[i];}底层源码中track收集依赖(get操作)。/***@description:*@param{target}目标对象*@param{type}集合的类型,下面是函数的定义*@param{key}触发track的对象的key*/exportfunctiontrack(target:object,type:TrackOpTypes,key:unknown){//activeEffect为空表示没有依赖,直接返回if(!shouldTrack||activeEffect===undefined){return}//targetMap依赖管理center,用于收集依赖,触发Dependency//检查targetMap中是否有当前targetletdepsMap=targetMap.get(target)if(!depsMap){//如果没有,新建一个targetMap.set(target,(depsMap=newMap()))}//deps收集依赖函数,当监听到的key值发生变化时,触发dep中的依赖函数letdep=depsMap.get(key)if(!dep){depsMap.set(key,(dep=newSet()))}if(!dep.has(activeEffect)){dep.add(activeEffect)activeEffect.deps.push(dep)//开发环境会触发onTrack,只针对debuggingif(__DEV__&&activeEffect.options.onTrack){activeEffect.options.onTrack({effect:activeEffect,target,type,key})}}}//get,has,iterate三种读取对象会触发trackexportconstenum轨道OpTypes{GET='get',HAS='has',ITERATE='iterate'}4.嵌入现有项目ExperimentbeforedefiningthestatebeforeupdatethestateNowdefinethestateNowupdatethestate5.Riskpointifyou认真看,其实这段代码是有风险的代码。我们使用for循环获取属性来收集依赖项。这正是问题所在。每次更新状态,都会触发for循环。要知道,如果有很多键,那是避免不了的。带来了性能问题。在Vue2.0中,会使用一个__ob__属性来标识是否被依赖项收集。已经收藏了,就不会再收藏了!vue3的采集方式和2.0有点不一样。Vue3.0引用的时候会收集。比如我们调用this.obj的时候,会收集obj下的属性。已经收录过的就不收录了,没有收录过的会重新收录。而使用WeakMap,一旦不需要,它就会自行消失。好吧,让我们回到最初的问题。我们在reactjsx中引用的属性不能像vue3处理template模板那样收集依赖,所以第一次更新后responsive对象就不再需要回收了,所以第二次就更新不了一次,所以每次都需要遍历一次.6.结语如果文中有什么不对或写得不好的地方,请大家指正,谢谢!码字不易,请点赞关注!说句题外话,笔者在“深圳Shopee”这家口碑不错的东南亚电商,2021年大量招人,机会多多!加入我们!现在或者以后有想法的同学可以加我微信【石头---999??】!邀请您加入我们的大家庭!参考https://vue3js.cn/vue-composite...https://juejin.cn/post/694783...
