前言
emm 由于實習(xí)的項目組只有自己一個人,選型開發(fā)都為所欲為了tat,從以redux進(jìn)行數(shù)據(jù)流管理的使用跨释,決定嘗試一波實戰(zhàn)mobx送丰,在使用中不禁在想酿傍,mobx是怎么和react連在一起炉媒,而mobx又是為什么可以如此高效便捷踪区。react-redux的驅(qū)動視圖更新是通過connect
組件,在外層HOC中訂閱store改變觸發(fā)
setState({})
進(jìn)行更新視圖。而mobx-react中的observer呢橱野?
這里可以看到最關(guān)鍵的一點,區(qū)別于redux的更新方式,在mobx-react中是直接使用forceUpdate
方法進(jìn)行更新視圖,而區(qū)別于redux 對store的訂閱,mobx-react又是怎么樣觸發(fā)forceUpdate呢?
/**
*強(qiáng)制更新組件https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L188
*/
Component.prototype.forceUpdate.call(this)
定位到observer,先了解observer執(zhí)行的流程
核心點
talk is so cheap show you the code
//...
// https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L334
mixinLifecycleEvents(target)
//mixin組件的生命周期,將reactiveMixin中的函數(shù)mixin到具體的生命周期中.
在mixin中最核心需要關(guān)注的就是componentWillMount,
先簡單提一下mixinLifecycleEvents
區(qū)別對待的是shouldComponentUpdate
,如果該方法沒有定義observer
會直接將其重寫為PureComponent
的shouldComponentUpdate
的實現(xiàn)
進(jìn)一步看componentWillMount
//https://github.com/mobxjs/mobx-react/blob/master/src/observer.js#L168
// wire up reactive render
//保存當(dāng)前函數(shù)的render
const baseRender = this.render.bind(this)
let reaction = null
let isRenderingPending = false
const initialRender = () => {
/*綁定reaction善玫,observable屬性改變的時候會觸發(fā)這個(mobx實質(zhì)是雙向綁定水援,observable更新視圖也要更新,這里是數(shù)據(jù)綁定到視圖上的第一步茅郎。)
*/
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
/**
* 核心關(guān)聯(lián)部分
* 追蹤數(shù)據(jù)
* https://github.com/mobxjs/mobx/blob/master/src/core/reaction.ts#L112
* reaction.track(fn: () => void)
* 實際上
* trackDerivedFunction<T>(derivation: IDerivation, f: () => T, context)
* const result = trackDerivedFunction(this, fn, undefined)// this對應(yīng)reaction,fn對應(yīng)track中的fn
* (https://github.com/mobxjs/mobx/blob/master/src/core/derivation.ts#L131)
* trackDerivedFunction這個函數(shù)有什么作用蜗元?
* 執(zhí)行函數(shù)f并跟蹤那些可觀察并且正在f函數(shù)中引用的變量,將這些可追蹤的變量注冊并儲存在derivation中即reaction中
*
* f中引用的變量 核心上是通過atom.reportObserved()關(guān)聯(lián)引用
* 簡單例子見 makePropertyObservableReference 中的
* get: function() {
* atom.reportObserved()
* return valueHolder
* },
*
* 重新到trackDerivedFunction執(zhí)行中
* result = f.call(context);
*f本身已經(jīng)是箭頭函數(shù)了,上下文已經(jīng)綁定過了. 這里實際上就是執(zhí)行component的render,
*實際上就是通過這里收集到observable的引用 (依賴收集)
*trackDerivedFunction中會derivation進(jìn)行屬性更新,以及通過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
},
這一次的閱讀之行到此就暫告一段落了,關(guān)于derivation原理的進(jìn)一步理解需要進(jìn)一步學(xué)習(xí)mobx的源碼奕扣。目前只是有較淺的理解,如有不正之處,請大家指出掌敬! tat 畢竟只是閉門造車惯豆。