vue3知识点总结

vue3知识点总结

(个人总结使用,只能保证我自己看得懂,看不懂的可以留言交流)

reactive 响应式系统

vue3 的响应式系统是基于订阅发布者模式,通过 proxy 实现对数据的响应式化,
而依赖副作用的收集就是根据响应式化的数据来进行的。
因为 Proxy 本质上是对某个对象的劫持,这样它不仅仅可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除;
Object.defineProperty 是给对象的某个已存在的属性添加对应的 gettersetter,所以它只能监听这个属性值的变化,而不能去监听对象属性的新增和删除。

注意
这里需要明确的一点,`reactive` 只是做了数据的响应式化处理,使用 `proxy` 代理数据对象,并在 `get`、`set` 中完成了数据访问劫持和数据设置触发依赖。 `get` 和 `set` 是在有访问或设置操作进行是才会触发的, 而 `vue` 的依赖收集(track)实际上是要结合 `effect Api` 进行的。 例如:
let foo = reactive('foo')   
let consoleFoo = ()=>{
      
    console.log(foo)   
}   
effect(consoleFoo)   

在上述代码中,首先通过 reactivefoo 做了代理,而 consoleFoo 方法则访问了 foo 并打印,
然后在 effect 中传入的函数 consoleFoo,在这个过程中,effect 会运行一遍传入的函数 consoleFoo
此时 consoleFoo 会被当做当前激活依赖存放在全局变量 activeEffect 上,而 consoleFoo 运行时访问了 foo,此时会触发 get,从而将当前的
activeEffect(也就是 consoleFoo),当做 foo 的依赖进行收集。

reactive 的基本实现

reactive API 的实现其实就是创建并返回了一个 proxy 对象,
将原始数据对象 rawmutableHandlers 传递给 proxy 构造函数,
完成对象的响应式代理。
其中 mutableHandlers 位于 baseHandlers.ts 中,其具体实现中
Getter 实现数据访问劫持:
Getter 接受两个参数 isReadonly = false,isShallow = false,用于标记是否创建的是 readonlyshallow
并且 返回了一个 get 方法,在 get 方法内部

  • 首先判断访问的 key 是否是 __v_reactive__v_readonly,并返回(isReadonlyisReactive 实现),
  • 然后根据 Getter 接受两个参数判断 isReadonly = false,则调用 track 做依赖收集。
  • 判断 isShallow = true,直接返回访问目标值 res
  • 如果访问目标值 res是对象,则根据 isReadonly 判断递归调用 readonly Apireactive Api 并传入 res

setter 实现数据设置派发更新:
将访问的目标对象 target、设置的 key,设置的值传递 trigger 方法 派发啊更新

effect的基本实现(runner、scheduler、stop)以及依赖收集与触发依赖

effect 主流程

effect 接受参数 effect 接受依赖函数 fn 和配置对象(内含调度执行函数 scheduleronStop方法),

  • 方法内部会通过 ReactiveEffect 创建 _effect 对象(_effect 接受依赖函数fn,和调度执行函数 scheduler ),
  • 然后会将 onStop 通过 Object.assign 拷贝到 _effect
  • 执行 _effect.run (其实这里就是执行了 依赖函数 fn,因为创建 _effect 时已经传递进去了),此时如果 fn 内部访问了 响应式对象,fn则会当做依赖被收集到对应 响应式对象依赖中。
  • 创建 runner _effect.run.bind(_effect)),并把 _effect 存在 runner 上(实现 stop 方法)
  • 返回 runner_effect.run.bind(_effect)),用户可以手动通过 runner 触发依赖,
ReactiveEffect 对象
_fn // 依赖函数   
deps = [] // 依赖函数集合   
active = true // 是否激活,stop方法执行后用于判断   
onStop = ()=>{
   } // stop 钩子方法   
scheduler

首先依赖收集有全局变量 activeEffect(当前激活的 effec t对象,内含副作用依赖),shouldTrack(是否需要收集)
ReactiveEffect 对象还包含一个 run 方法 和 stop 方法,
在构造方法时,_fn 会缓存当前传入的依赖函数 fn
当外部调用 run 方法时,run 方法内部会先判断 active === false,
命中则直接返回 依赖函数执行结果 this._fn()
否则 shouldTrack 设置为 true
就把 activeEffect 指向当前 ReactiveEffect 对象(用于 track 时收集),
执行结果 res = this._fn();
shouldTrack 设置为 false
最后返回 res
注意,实际上 activeEffect 指向当前 ReactiveEffect 对象这一步是通过effectStack 栈 维护的

const counter = reactive({
      
num: 0,   
num2: 0   
})   
function logCount() {
      
effect(logCount2)   
console.log('num:', counter.num)   
}   
function count() {
      
counter.num++   
}   
function logCount2() {
      
console.log('num2:', counter.num2)   
}   
effect(logCount)   
count()   

上述代码中,如果单纯的把activeEffect 指向当前 ReactiveEffect 对象,effect(logCount2)
执行完后 activeEffect 指向的是 logCount2,而后续的 console.log('num:', counter.num) ,
会导致错误的将 logCount2作为 num的依赖收集,
此时我们count(),触发的依赖却是 logCount2,在 fn 执行完毕后出栈,再把 activeEffect 指向 effectStack 最后一个元素,
也就是外层 effect 函数对应的 reactiveEffect

当外部调用 stop 方法时,stop 方法内部会先判断 active === true,
然后判断是否传入了 onStop 钩子函数,有就运行 onStop。然后清除依赖,并把 active = false,

注意
`stop` 方法想要实现的效果其实是 `stop` 后,清空收集的依赖并不在收集、不执行副作用函数,需要手动调用 `runner`, 这个效果实际上是通过 `shouldTrack` 和 `this.active` 实现的 正常情况下 `run` 方法运行,`shouldTrack` 设置为 `true` ,然后执行 `this._fn()`,在这个 `this._fn()` 过程中会触发 `track` 做依赖收集, 而 `track` 会判断 `shouldTrack`,为 `false` 直接返回不收集, 正常流程 `shouldTrack = true =》this._fn() =》 track 收集 =》shouldTrack = false`, 注意此流程走完后依赖收集完毕是 `false` 的, 而在调用 `stop` 方法后因为 `this.active` 变为 `false`,`run` 方法运行他会直接返回 `this._fn()` 的结果,不会在设置 `shouldTrack = true`,于是在 `track` 时会被直接返回捕收剂。 #### 为什么effect.run 每次运行都要清空effect对象上的依赖? 见 `why should cleanupEffect in ReactiveEffect` ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— #### stop方法Api `stop`方法`Api`,传入一个 `runner`,当 `trigger` 后 ,不执行副作用函数,需要手动调用 `runner`, 其内部就是通过传入的 `runner` 访问都 `effect` 对象,并调用 `effect` 对象上的 `stop` 方法
track

先判断 shouldTrack,为 false 直接返回不收集
全局维护了一个 targetMapkey 是响应式原始对象 target,值是 depsMap
depsMapkeytarget 中的各个 key,值是一个 deps(本质是 Set ),
deps 中每个元素是都对应这这个 key 的一个 activeEffectReactiveEffect 对象,依赖函数 fn 实际上就存储在 ReactiveEffect_fn上)
track 方法主要是对上述数据结构的一些维护,比如没有就创建,有就获取,最终创建或找到对应 target 的对应 key 的依赖集合 deps,然后调用 trackEffectsactiveEffect 收集到 deps 中,
值得注意的时 trackEffects 还反向收集 activeEffect.deps.push(dep),在清除依赖时使用

trigger

depsMap 中找到对应 target 对应 keydeps,并

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值