前言
vue3的reactivity源码地址
- reactivity 响应式系统
- 实现的composition API有:
- computed
- 默认不执行, 通过
lazy = true
是去判断
- 多次取值时要实现缓存, 通过
dirty = true
, 判断是脏的 就去执行传递的函数, 然后dirty = false
- 将传递的函数封装成effect, 将其将函数里的依赖的响应式变量 收集computed effect
- computed取值时要做依赖收集track(vue2 是依赖值做的全部收集 即收集computed watcher , 也要收集渲染 watcher)
- 当依赖值发生变化时, 发布effect时 判断当前effect是 computed effect
effect.options.scheduler
- 将
dirty = true
, 并且trigger, computed取值时收集的effect
- 具体以下方示例为主
示例
<script src="../node_modules/@vue/reactivity/dist/reactivity.global.js"></script>
<div id="app"></div>
<script>
let { effect, reactive, ref, shallowRef, toRef, toRefs, computed } = VueReactivity
const age = ref(18)
const myAge = computed(() => {
return age.value + 10
})
effect(() => {
app.innerHTML = myAge.value
})
setTimeout(() => {
age.value = 100
}, 2000)
</script>
+---------------------+ +----------------------+
| | | |
| 28 +--->| 110 +
| | | |
+---------------------+ +----------------------+
shared
export const isObject = (value) => typeof value == 'object' && value !== null
export const extend = Object.assign
export const isArray = Array.isArray
export const isFunction = (value) => typeof value == 'function'
export const isNumber = (value) => typeof value == 'number'
export const isString = (value) => typeof value === 'string'
export const isIntegerKey = (key) => parseInt(key) + '' === key
let hasOwnpRroperty = Object.prototype.hasOwnProperty
export const hasOwn = (target, key) => hasOwnpRroperty.call(target, key)
export const hasChanged = (oldValue,value) => oldValue !== value
computed.ts
import { isFunction } from "@vue/shared/src"
import { effect, track, trigger } from "./effect"
import { TrackOpTypes, TriggerOrTypes } from "./operators"
class ComputedRefImpl {
public _dirty = true
public _value;
public effect;
constructor(getter, public setter) {
this.effect = effect(getter, {
lazy: true,
scheduler: () => {
if (!this._dirty) {
this._dirty = true
trigger(this, TriggerOrTypes.SET, 'value')
}
}
})
}
get value() {
if (this._dirty) {
this._value = this.effect()
this._dirty = false
}
track(this, TrackOpTypes.GET, 'value')
return this._value
}
set value(newValue) {
this.setter(newValue)
}
}
export function computed(getterOrOptions) {
let getter;
let setter;
if (isFunction(getterOrOptions)) {
getter = getterOrOptions
setter = () => {
console.warn('computed value must be readonly')
}
} else {
getter = getterOrOptions.get
setter = getterOrOptions.set
}
return new ComputedRefImpl(getter, setter)
}
export function trigger(target, type, key?, newValue?, oldValue?) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const effects = new Set()
const add = (effectsToAdd) => {
if (effectsToAdd) {
effectsToAdd.forEach(effect => effects.add(effect))
}
}
if (key === 'length' && isArray(target)) {
depsMap.forEach((dep, key) => {
if (key === 'length' || key > newValue) {
add(dep)
}
})
} else {
if (key !== undefined) {
add(depsMap.get(key))
}
switch (type) {
case TriggerOrTypes.ADD:
if (isArray(target) && isIntegerKey(key)) {
add(depsMap.get('length'))
}
break;
}
}
effects.forEach((effect: any) => {
if(effect.options.scheduler){
effect.options.scheduler(effect)
}else{
effect()
}
})
}
完