Vue3.0 响应式系统源码逐行分析讲解(6)

{ _isRef: true, // expose effect so computed can be stopped effect: runner, get value() { if (dirty) { value = runner() dirty = false } trackChildRun(runner) return value }, set value(newValue) { if (setter) { setter(newValue) } else { // TODO warn attempting to mutate readonly computed value } } }

先说说set吧,尤大似乎还没写完,只是单纯能修改值

然后是get,注意dirty的变化,如果computed依赖了state中的值,初次渲染时,他会调用依赖,然后dirty = false,关键来了,最后执行了trackChildRun

function trackChildRun(childRunner: ReactiveEffect) { const parentRunner = activeReactiveEffectStack[activeReactiveEffectStack.length - 1] if (parentRunner) { for (let i = 0; i < childRunner.deps.length; i++) { const dep = childRunner.deps[i] if (!dep.has(parentRunner)) { dep.add(parentRunner) parentRunner.deps.push(dep) } } } }

由于computed是依赖了state中的属性的,一旦在初始时触发了get,执行runner,就会将依赖收集到activeReactiveEffectStack中,最后才是自己的依赖,栈的顶部是state属性的依赖

if (!dep.has(parentRunner)) { dep.add(parentRunner) parentRunner.deps.push(dep) }

所以最后这段代码实现了state属性变化后,才导致了computed依赖的调用,从而惰性求值

ref

const convert = (val: any): any => (isObject(val) ? reactive(val) : val) export function ref<T>(raw: T): Ref<T> { raw = convert(raw) const v = { _isRef: true, get value() { track(v, OperationTypes.GET, '') return raw }, set value(newVal) { raw = convert(newVal) trigger(v, OperationTypes.SET, '') } } return v as Ref<T> }

ref的实现真的很简单了,前面已经学习了那么多,相信大家都能看懂了,区别就是convert(raw)对传入的值进行了简单判断,如果是对象就设置为响应式,否则返回原始值。

最后

终于分析完了,Vue3.0响应系统使用了Proxy相比于Vue2.0的代码真的简洁许多,也好理解,说难不难。其实还有watch并没有讲,它没有在reactivity中,但是实现还是使用了effect,套路都是一样的。最后谢谢大家观看。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/23dafa4f1d3ac97518ded955668ba551.html