Mobx是一個狀態管理的庫, 也許你對應用中一些數據的管理已經駕輕就熟了,而且有本身擅長或喜愛的狀態管理庫,但這也並不會影響你對Mobx展開了解,由於這些庫或者工具提供給咱們的是解決問題的方案,存在即有其合理性,既然Mobx存在,並受到很多人的推崇,那確定有其優點所在,基於這個緣由,咱們也是能夠花那麼一丟丟時間去熟悉下的,也許會對咱們有莫大的幫助。我也是基於這麼個想法去了解熟悉了下mobx,並作個總結。vue
mobx是一個狀態管理的庫,它不依賴於視圖層的框架, 不像vuex,是vue的定製版。它與任何的視圖層框架都是能夠配合使用的, 可是和它最配的就是React了。但是React不是已經有了黃金搭檔Redux麼, 爲啥還出來一個第三者呢,而且還受到很多人的喜好, 連Redux的做者都推薦過mobx,還有很多人將應用從Redux重構爲Mobx。這說明Mobx確實有其吸引人的地方,這裏不談二者的對比,這一系列文章仍是比較多的,不過能夠先從這裏入手一波Mobx。react
Demo1:
import { observable, autorun } from 'mobx'
const obsObj = observable({
title: 'hello world'
})
autorun(() => {
console.log('mobx observal title',obsObj.title)
})
obsObj.title = 'title change'
複製代碼
輸出的結果是:git
otuput:
mobx observal title: hello world
mobx observal title: title change
複製代碼
將一個對象經過observable方法變爲可觀察的, 執行aurorun中的函數, 狀態變動後autorun中的函數自動的再次執行。能夠看出Mobx自身實現了一套響應式原理,沒讀過源碼, 但大體能夠知道其實現使用了觀察者模式,第一遍執行autorun時有調用對象屬性的對方對其get方法進行攔截, 並將這個函數加入到其依賴中, 在執行set的時候,執行收集的依賴。其中autorun就是原來圖中的reaction衍生, state就是observable以後的可觀察狀態對象。github
Demo2:
import {observable, autorun, action} from 'mobx'
const obsObj = observable({
title: 'hello world',
get extendTitle() {
return `${this.title} mobx`
}
})
autorun(() => {
console.log('mobx computed title:', obsObj.extendTitle)
})
const fn = action(function(){
obsObj.title = 'title change'
})
fn()
複製代碼
輸出結果是:vuex
otuput:
mobx computed title:' hello world mobx mobx observal title: title change mobx 複製代碼
相比上個例子,多了一個computed屬性, 即extendTitle, 它也是會變爲可觀測的, 能夠知道extendTitle依賴了title,因此title變了後, computed自動生成新的值,而autorun依賴的extendTitle變了,因此再次自動執行。(值得注意的是若沒有計算屬性是隻有運用到時纔會去執行從新計算邏輯)。還有一個action, 它是將要變動數據的方法用action包裹一下, 這個不是必須的, 可是在大型複雜應用中這是頗有必要的,由於狀態的變動必定是發生在action裏, 更容易定位問題。 所以mobx有配置參數能夠設置更改observable的數據必需要用action包裹。chrome
至此mobx的執行流程以及重要的概念已經經過上述的兩個demo比較清晰的理解了。redux
mobx的api也是比較簡單而且好理解的,能夠將其分爲 三類, 上面的demo中使用的api都有各自的歸屬, 這部分簡單講下這三類api,固然是自我理解後的一些精華部分, 具體並完整的那莫過於官網了, 而且也不是一篇文章能講完的。api
mobx能夠將JS基本數據類型、引用類型、普通對象、類實例、數組、映射、Set變爲一個可觀察的數據。數組
這是一個便捷的api,observable(value), 只有value是object(普通對象), Array, Map, Set能轉換成功。原始數據類型、非普通對象、函數會報錯。 注: 普通對象指的是一個對象的原型是Object,或者沒有原型,即用花括號建立的對象字面量或者Object.create(null)建立的對象promise
能夠是任何數據,通常用於基本數據類型,設置和獲取以及變爲可觀測的使用方式和observable有所不一樣。例如官網的一個demo:
import {observable} from "mobx";
const cityName = observable.box("Vienna");
console.log(cityName.get());
cityName.observe(function(change) {
console.log(change.oldValue, "->", change.newValue);
});
cityName.set("Amsterdam");
複製代碼
extendObservable用於將用構造函數生成的對象以及Object.create原型非null的對象變爲可觀察。
var Person = function(firstName, lastName) {
// 在一個新實例上初始化 observable 屬性
extendObservable(this, {
firstName: firstName,
lastName: lastName,
get fullName() {
return this.firstName + " " + this.lastName
},
setFirstName(firstName) {
this.firstName = firstName
}
}, {
setFirstName: action
});
}
var matthew = new Person("Matthew", "Henry");
extendObservable(matthew, {
age: 353
});
複製代碼
以上幾個api基本上完成了絕大多數咱們應用的訴求,將數據變爲可觀察。
reactions指的是對可觀察的數據作出相應,能夠是產生一個新的值, 也能夠是產生一些反作用, 好比打印日誌,更新視圖等的邏輯。
很是好理解的一個api, 就是計算屬性, 會根據依賴的可變化數據生成一個新的值, 而且這個新的值也是可觀察。mobx對性能上是作到了很好的優化的,這個計算屬性的值,在某輪狀態變化的過程當中沒有被用到,那麼它是不會被從新計算執行的,而且若是這個值再也不被引用了, 那麼也會被垃圾回收掉。
這個就是響應式函數, 依賴的狀態變化後, 自動執行該函數, so easy。
這兩個徹底能夠看作是autorun的語法糖,是autorun功能的一個加強。官網看下api很是好理解的。
注意點: 咱們要弄清楚衍生它會對什麼作出響應,MobX 會對在追蹤函數執行過程當中讀取現存的可觀察屬性作出反應。就是在衍生裏執行了讀取可觀察屬性的操做,則它會響應後續的狀態變動。
action就是動做, 觸發可觀察狀態的變動, 造成一個閉環,從上面的兩個demo其實能夠看出,action包裹並非必須的,可是大型應用中將一些數據變動的操做都強制用action包裹是頗有必要的, 這樣對系統的維護性以及排查問題仍是頗有用的。
若是須要將動做強制action包裹, 須要全局配置mobx的config:
const { configure} from "mobx"
configure({
enforceActions: 'always'
});
複製代碼
若是action包裹的函數中存在異步的回調函數(promise的then,setTimeout裏的回調), 若是裏面改變了狀態則也須要用將其用action包裹,runInAction它也是action的語法糖, 將異步回調中的最終的狀態修改的部分放到一個函數中,用runInAction包裹。
將異步用generator的方式寫,而後用flows包裹。
上面的那些三類api就是mobx的思想所在, 可是mobx正真方便使用姿式是裝飾器模式。以下使用裝飾器的兩個demo所示, 包含以上三類api的使用:
demo1:
import { observable, computed, autorun } from "mobx";
class OrderLine {
@observable price = 0;
@observable amount = 1;
@computed get total() {
return this.price * this.amount;
}
}
const obj = new OrderLine()
autorun(() => {
console.log(obj.amount)
})
obj.amount = 2
複製代碼
上述是在babel或者ts的轉換下,支持用裝飾器寫法的一個coding, 若是不支持, 也提供了decator api以下:
demo2:
import { observable, computed, action, decorate } from "mobx"
class OrderLine {
price = 0;
amount = 1;
get total() {
return this.price * this.amount;
}
setPrice() {
this.price = 2
}
}
decorate(OrderLine, {
price: observable,
amount: observable,
total: computed,
setPrice: action,
})
複製代碼
mobx內置了trace API,該API能夠幫助咱們在開發的時候進行調試。能夠經過在衍生中(computed,autorun等響應函數)加入trace(true),可以在響應狀態變化時進行debugger,經過調試信息咱們可以看出是哪一個狀態的變化觸發了它的響應、這個衍生依賴哪些狀態,以及定位這次變化的代碼。
Demo:
import {observable, autorun, trace} from 'mobx'
const obsObj = observable({
title: 'hello world',
name: 'trace demo'
})
autorun((r) => {
trace(true)
console.log('name: ', obsObj.name)
})
obsObj.name = 'title changed'
複製代碼
上面demo中,可觀察狀態obsObj.name發生變化時,自動執行autorun, 而後在chrome能夠看到以下的斷點信息:
經過上述mobx的瞭解,大概知道其如何運行以及一些重要的api,它是不依賴於視圖層框架的, 即它能夠和咱們主流的React、VUE、Angular結合的,只須要一個鏈接器,但它還算和React搭配運用的最多了。友mobx原理不難理解, 只須要將視圖的render做爲一個衍生就好了,render裏的狀態都變爲可觀察的,狀態變了就從新render,更新視圖。即以下圖所示:
以上是mobx一些主要的思想以及api, 經過這邊文章能夠用更少的時間去了解上手mobx, 若是須要深刻能夠仔細去研讀mobx的官網了,以及mobx和redux的對比文章也是能夠搜索出很多的。