mobx.box
用来包裹原始值类型的可观测包装
const x = observable.box(3)
- 新建new ObservableValue管理value=3
- enhancer默认为deep=true的deepEnhancer 深度遍历构造可观察
- ObservableValue包裹3后,控制包裹层的行为,定义get set行为
- get执行时,广播到上层自己是个可观察的数据,需要被收集,然后返回具体值
- set执行时,如果有拦截器,值不合法则放弃更新,更新后,查看新值是否需要遍历构造观察模型,防止3 => {xxx: 3}
- setNewVal_执行具体赋值工作,唤醒监听器handler执行
- intercept_注册拦截器,对值校验
- toJSON访问一次get()
mobx.array
包装数组 支撑某些工具方法具备可观察特点
proxy拦截一些操作,包装处理
values用于存放数据,任何操作都是在values上替换元素 包括splice,pop等
访问一些不影响原数组的api时,转化为正常数组,再进行操作,比如map filter等
const a = observable.array([])
- 新建new ObservableArrayAdministration 是数组可观察
- intercept拦截器,interceptors= []
- observe 注册监听器 changeListeners = []
- getArrayLength获取数组长度 广播上报自己是可观察对象且被当前外层观察
- setArrayLength,如果长度新>旧,补充空元素,如果旧>新 删除多余元素,调用的方法是spliceWithArray
- spliceWithArray_,判断传入的index合法性,且可以添加新成员替换,如果有拦截器且操作非法,类似splice,返回空数组,表示无操作成功元素
- updateArrayLength_, spliceItemsIntoValues找准位置插入
- notifyArraySplice_通知有变
- new Proxy管控真实数组的get set 数组被proxy处理后,访问下标都是字符串形式 xx[1] => proxy[‘1’]
- get处理,如果访问的是length,adm.getArrayLength_
- 拦截原生方法,改造成有广播功能的方法 比如splice, shift, pop, push等
- set处理,实际执行adm.set_,进行拦截器预先处理,然后广播变化,且enhancer来处理,决定是否需要对新增或者改变的元素深度遍历监听 看起来不能直接 xx = []这样清空了 新增了clear方法完成这个工作
- 不对原数组进行改变操作的就不去动它 让它访问原始值 concat,flat, includes, indexOf, join, lastIndexOf,slice, toString, toLocaleString,every,filter等
mobx.map
const x = mobx.observable.map({ a: 3 })
- new ObservableMap() 构建观察管理员 观察目标数据
- adm的merge处理数据初始化,再调用set方法逐个key-value设置
- 询问是否有拦截器,拦截器处理
- 如果之前存在key,则updateValue,否则新增addValue
- 开启事务 操作结束前不通知任何观察着
- new ObservableValue(value)观察key对应的value
- 查看是否有监听者 广播通知变更
- 如果是updateVlaue_,设置新的key对应的value,且通知监听者
- 包装keys,values, entries等api的可监听性
mobx.set
类似map
mobx.set(a, "x", 0)
- new ObservableSet()
- 包装keys, entries,delete,add等api
mobx.object
mobx.object({x: 1})
- 创建一个被观察的对象的管理员 adm = new ObservableObjectAdministration()
- getOwnPropertyDescriptors获取对象的所有自身属性
- 开启proxy,代理target {x: 1}
- 开启batch,调用adm的extend通过defineProperty扩展,后续会发出新增属性通知
- 对象的属性扩展中 改写get,使之成computed包裹类型
- 改写set,使之能触发action,
- 继续扩展 遍历value是否需要深度包装
mobx.observe_
注册监听
const x = observable.box(3)
m.observe(x, func)
- 获取observable对象的adm,可观察对象的管理者 ObservableValue, ObservableArrayAdministration,ObservableMap,ObservableSet,ObservableObjectAdminisration
- 调用注册的observe_方法添加监听器changeListeners = []
- 变更通知,去除changeListeners中的handler执行
批量处理的含义
const x = observable.box(3)
const y = observable.box(2)
const z = computed(function () {
return x.get() * y.get()
})
startBatch() // 开始批量处理 进入了computed包裹方法范围
this.value_ = this.computeValue_(false) // 这边回执行到x.get y.get
endBatch()
// this.value_ = this.computeValue_(false) // 这边回执行到x.get y.get
reportObserved(this) // 都会收集监听者 computed
if (shouldCompute(this)) {
let prevTrackingContext = globalState.trackingContext
if (this.keepAlive_ && !prevTrackingContext) globalState.trackingContext = this
if (this.trackAndCompute()) propagateChangeConfirmed(this)
globalState.trackingContext = prevTrackingContext
}
// 如果是这种深度嵌套是怎么处理呢
const x = observable.box(3)
const y = observable.box(2)
const z = computed(function () {
return x.get() * y.get()
})
const e = computed(function () {
return z.get()
})
Observable
observable.box
const x = observable.box(3)
// 1. observableFactories.box
box<T = any>(value?: T, options?: CreateObservableOptions): IObservableValue<T> {
const o = asCreateObservableOptions(options)
return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)
},
// 1.1 asCreateObservableOptions(options) // options = undefined
//options 是否deep监听 是否用proxy
{
deep: true,
name: undefined,
defaultDecorator: undefined,
proxy: true
}
// 2. 对原始值的处理
ObservableValue(value) //包裹原始值
// 3. 初始值 enhancer(value, undefined, name_) 完成简单的注册
export function deepEnhancer(v, _, name) {
// it is an observable already, done
if (isObservable(v)) return v // new ObservableValue命中 是已观测的
...
}
// 4. 与computed合作
// const x = observable.box(3)
const z = computed(function () {
return x.get() * 2
})
// 5. 建立一个computed观察对象
const opts: IComputedValueOptions<any> = isPlainObject(arg2) ? arg2 : {}
// get = computed包裹的那个方法
opts.get = arg1
opts.name ||= arg1.name || "" /* for generated name */
return new ComputedValue(opts) // 返回一个ComputedValue包裹的值
// 6. new ComputedValue主要属性
this.derivation = options.get!
this.setter_
this.get()
this.set
// 7. z.get()
// 7.1 globalState.inBatch === 0非批处理 this.observers_.size === 0无观察者就开始计算
this.value_ = this.computeValue_(false) // track = false 无跟踪
// 7.2 传入的上下文context可以作为scope取参数
res = this.derivation.call(this.scope_) // this.derivation = 包裹的方法
// 9. 执行过程中 触发到了x 收集x的依赖集合数组 x.get() 上报被监听了
reportObserved(this) // this = box(3) = ObservableValue
// 10. box(3)的监听者收集为空 且inBatch > 0(在监听者中执行) 就收集当前监听者
observable.observers_.size === 0 && globalState.inBatch > 0
// 11. 开始收集
queueForUnobservation(observable)
// 12. 当前这个box(3) 被监听了 自己在执行中 标记自己是被监听中的收集状态 在computed的执行范围中
export function queueForUnobservation(observable: IObservable) {
if (observable.isPendingUnobservation_ === false) {
// invariant(observable._observers.length === 0, "INTERNAL ERROR, should only queue for unobservation unobserved observables");
observable.isPendingUnobservation_ = true
globalState.pendingUnobservations.push(observable) // 全局pengding
}
}
// 13. 上报结束后 需要endBatch computed的
computed去拿值都能拿到最新的 并没有去设定这个监听 box没有收集computed 要收集的是reaction reaction中可能包含computed