本文从源码层面进行分析,结合了实际vue
项目经验,梳理vue
的依赖收集,分析的vue
版本为3.3.3
本文适合有一定实战经验或阅读经验的vue
开发者
响应式基础
在了解依赖收集前,我们先了解下vue
是如何书写响应式的。
1 2 3 4 5
| <template> <div>count:{{ count }}</div> <div>data:{{ data.count }}</div> </template>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
const count = ref(0) count.value++ console.log(count.value)
const data = reactive({ count: 0 }) data.count++ console.log(data.count)
|
ref
响应式源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| export function ref(value?: unknown) { return createRef(value, false) }
export function shallowRef(value?: unknown) { return createRef(value, true) }
function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } return new RefImpl(rawValue, shallow) }
class RefImpl<T> { private _value: T private _rawValue: T
public dep?: Dep = undefined public readonly __v_isRef = true
constructor(value: T, public readonly __v_isShallow: boolean) { this._rawValue = __v_isShallow ? value : toRaw(value) this._value = __v_isShallow ? value : toReactive(value) }
get value() { trackRefValue(this) return this._value }
set value(newVal) { const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal) newVal = useDirectValue ? newVal : toRaw(newVal) if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal this._value = useDirectValue ? newVal : toReactive(newVal) triggerRefValue(this, newVal) } } }
|
在ref
读操作的时候会调用trackRefValue
,最终调用trackEffects
进行依赖收集
另一方面,依赖收集只会存在在watch
、computed
、template bind
等进行(watchEffect
)