1、执行下面代码
packages\vue\examples\composition\test.html
<script src="../../dist/vue.global.js"></script>
<div id="demo">
<h1>
<header>{{count}}</header>
<header>{{count2}}</header>
</h1>
</div>
<script>
const { createApp, ref, toRefs, reactive, watch, onMounted, computed } = Vue
var app = createApp({
setup() {
var count = ref(1)
var count2 = computed(() => {
debugger
return count.value * 2
})
setTimeout(() => {
count.value++
}, 1000);
return { count, count2 }
}
})
app.mount('#demo')
</script>
2、流程分析
- 执行
setupCompoent时,会执行computed函数 - 获取
getter和setter - 执行
new ComputedRefImpl(getter, setter),内部代码分成下面两个部分:this.effect = new ReactiveEffect( getter , fn )- 当
count.value++时,则执行effect.schedule,于是执行fn - fn函数先判断
this._dirty === false - 如果是,则
this._dirty = true,且执行triggerRefValue,否则啥也不干 - 执行
triggerRefValue时,内部会执行effect.schedule(),于是执行() => queueJob( instance.update )
- 当
get value(){ }- componentUpdateFn执行patch时访问到了该计算属性的值,才会触发
get value(){ } - 如果触发了get value(){} ,则执行下面步骤:
- 执行
trackRefValue(),收集上面声明的this.effect 和 响应式数据关联,当count.value++时,触发上面的fn if(self._dirty === true)- 是则,
self._dirty = true, 且self._value = self.effect.run() - 否则,说明
self._dirty是false,直接返回self._value
- componentUpdateFn执行patch时访问到了该计算属性的值,才会触发
3、代码分析
packages\reactivity\src\computed.ts
function computed(
getterOrOptions,
debugOptions
) {
let getter
let setter
const onlyGetter = isFunction(getterOrOptions)
if (onlyGetter) {
getter = getterOrOptions
setter = NOOP
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set
}
const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter,isSSR)
return cRef
}
class ComputedRefImpl {
public _dirty = true
constructor(getter , private readonly _setter) {
this.effect = new ReactiveEffect(getter, () => {
if (!this._dirty) {
this._dirty = true
triggerRefValue(this)
}
})
}
get value() {
const self = toRaw(this)
trackRefValue(self)
if (self._dirty || !self._cacheable) {
self._dirty = false
self._value = self.effect.run()!
}
return self._value
}
set value(newValue) {
this._setter(newValue)
}
}