computed
- computed 方法的核心是基于
effect, - computed 方法返回的是一个带有
.value属性的ComputeRefImp对象
const computed =(getterOrOptions) {
let getter;
let setter;
if(isFunction(getterOrOptions)) {
getter = getterOrOptions
setter = ()=> {
console.log('computed can not be set')
}
}else {
getter = getterOptions.get
setter = getterOrOpitons.set
}
const crf = new ComputedRefImp(getter,setter)
return crf
}
class ComputedRefImp {
_dirty = true;
deps = new Set()
effect = null
_value = null
construction(getter,setter) {
this.effect = new ReacitveEffect(getter, ()=> {
if(!this._dirty) {
this._dirty = true
triggerEffect(this.deps) // 执行依赖
}
})
}
get value () {
trackEffects(this.deps) // 收集副作用
if(this._dirty) {
this._dirty = false
this._value = this.effect.run(); // 收集副作用
}
return this._value
}
set value(newValue) {
this.setter(newValue)
}
}
watch
-
watch 方法是基于
effect -
参数
- reactive 对象,会被递归遍历
- callback 函数,里面返回一个值
-
返回值 newValue, oldValue, onCleanup
- 如果传入的是一个对象,那么新值和旧值无法区分,引用同一个地址
- 如果传入是一个函数,且返回的是一个原始值,那么新值和旧值可以区分
- onCleanup 接受一个 函数,用于在异步执行的时,对上一次的 watch callback 函数内部执行进行控制(利用闭包的原理)。
const watch = (source,callback)=> {
let getter;
let oldValue;
if(isReactive(source)) {
getter = ()=> travesal(source); // 递归的目的是为了收集响应式对象的每一层属性的副作用
}else if(isFunction(source)) {
getter = soruce
}else {
return
}
let cleanup;
const onCleanup = (cb) {
cleanup = cb
}
const job = ()=> {
if(cleanup) {
cleanup()
}
const newValue = this.effect.run()
callback(newValue,oldValue,onCleanup)
oldValue = newValue
}
this.effect = new ReactiveEffect(getter,job)
oldValue = this.effect.run() // 收集副作用
}
const travesal(value,set = new Set()) {
if(!isObject(value)) return value;
if(set.has(value)) {
return value
}
set.add(value)
let(key in value) {
travesal(value[key],set)
}
return value
}