前言
emm 由于实习的项目组只有自己一个人,选型开发都为所欲为了tat,从以redux进行数据流管理的使用,决定尝试一波实战mobx,在使用中不禁在想,mobx是怎么和react连在一起,而mobx又是为什么可以如此高效便捷。react-redux的驱动视图更新是通过connect
组件,在外层HOC中订阅store改变触发
setState({})
进行更新视图。而mobx-react中的observer呢?
这里可以看到最关键的一点,区别于redux的更新方式,在mobx-react中是直接使用forceUpdate
方法进行更新视图,而区别于redux 对store的订阅,mobx-react又是怎么样触发forceUpdate呢?
/**
*强制更新组件https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L188
*/
Component.prototype.forceUpdate.call(this)
定位到observer,先了解observer执行的流程
核心点
talk is so cheap show you the code
//...
// https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L334
mixinLifecycleEvents(target)
//mixin组件的生命周期,将reactiveMixin中的函数mixin到具体的生命周期中.
在mixin中最核心需要关注的就是componentWillMount,
先简单提一下mixinLifecycleEvents
区别对待的是shouldComponentUpdate
,如果该方法没有定义observer
会直接将其重写为PureComponent
的shouldComponentUpdate
的实现
进一步看componentWillMount
//https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L168
// wire up reactive render
//保存当前函数的render
const baseRender = this.render.bind(this)
let reaction = null
let isRenderingPending = false
const initialRender = () => {
/*绑定reaction,observable属性改变的时候会触发这个(mobx实质是双向绑定,observable更新视图也要更新,这里是数据绑定到视图上的第一步。)
*/
reaction = new Reaction(`${initialName}#${rootNodeID}.render()`, () => {
if (!isRenderingPending) {
// N.B. Getting here *before mounting* means that a component constructor has side effects (see the relevant test in misc.js)
// This unidiomatic React usage but React will correctly warn about this so we continue as usual
// See #85 / Pull #44
isRenderingPending = true
if (typeof this.componentWillReact === "function") this.componentWillReact() // TODO: wrap in action?
if (this.__$mobxIsUnmounted !== true) {
// If we are unmounted at this point, componentWillReact() had a side effect causing the component to unmounted
// TODO: remove this check? Then react will properly warn about the fact that this should not happen? See #73
// However, people also claim this migth happen during unit tests..
let hasError = true
try {
isForcingUpdate = true
if (!skipRender) Component.prototype.forceUpdate.call(this)
hasError = false
} finally {
isForcingUpdate = false
if (hasError) reaction.dispose()
}
}
}
})
reaction.reactComponent = this
reactiveRender.$mobx = reaction
// 重写render
this.render = reactiveRender
// 实际的render
return reactiveRender()
}
const reactiveRender = () => {
isRenderingPending = false
let exception = undefined
let rendering = undefined
/**
* 核心关联部分
* 追踪数据
* https://github.com/mobxjs/mobx/blob/master/src/core/reaction.ts#L112
* reaction.track(fn: () => void)
* 实际上
* trackDerivedFunction(derivation: IDerivation, f: () => T, context)
* const result = trackDerivedFunction(this, fn, undefined)// this对应reaction,fn对应track中的fn
* (https://github.com/mobxjs/mobx/blob/master/src/core/derivation.ts#L131)
* trackDerivedFunction这个函数有什么作用?
* 执行函数f并跟踪那些可观察并且正在f函数中引用的变量,将这些可追踪的变量注册并储存在derivation中即reaction中
*
* f中引用的变量 核心上是通过atom.reportObserved()关联引用
* 简单例子见 makePropertyObservableReference 中的
* get: function() {
* atom.reportObserved()
* return valueHolder
* },
*
* 重新到trackDerivedFunction执行中
* result = f.call(context);
*f本身已经是箭头函数了,上下文已经绑定过了. 这里实际上就是执行component的render,
*实际上就是通过这里收集到observable的引用 (依赖收集)
*trackDerivedFunction中会derivation进行属性更新,以及通过bindDependencies更新依赖收集的情况。
**/
reaction.track(() => {
if (isDevtoolsEnabled) {
this.__$mobRenderStart = Date.now()
}
try {
rendering = extras.allowStateChanges(false, baseRender)
} catch (e) {
exception = e
}
if (isDevtoolsEnabled) {
this.__$mobRenderEnd = Date.now()
}
})
if (exception) {
errorsReporter.emit(exception)
throw exception
}
return rendering
}
this.render = initialRender
},
这一次的阅读之行到此就暂告一段落了,关于derivation原理的进一步理解需要进一步学习mobx的源码。目前只是有较浅的理解,如有不正之处,请大家指出! tat 毕竟只是闭门造车。
注释版源码
学习资料
- http://www.cnblogs.com/rubylouvre/p/6058575.html
- https://zhuanlan.zhihu.com/p/27448262