簡單、可擴展的狀態管理javascript
MobX 是由 Mendix、Coinbase、Facebook 開源和衆多我的贊助商所贊助的。html
npm install mobx --save
。 React 綁定庫: npm install mobx-react --save
。 要啓用 ESNext 的裝飾器 (可選), 參見下面。小貼士: MobX 5 包的主入口點附帶 ES5 代碼,以便向後兼容全部構建工具。但由於 MobX 5 只能運行在現代瀏覽器上,因此能夠考慮使用速度最快、體積最小的 ES6 構建: lib/mobx.es6.js
。例如,經過設置 webpack 的別名: resolve: { alias: { mobx: __dirname + "/node_modules/mobx/lib/mobx.es6.js" }}
java
MobX 是一個通過戰火洗禮的庫,它經過透明的函數響應式編程(transparently applying functional reactive programming - TFRP)使得狀態管理變得簡單和可擴展。MobX背後的哲學很簡單:node
任何源自應用狀態的東西都應該自動地得到。react
其中包括UI、數據序列化、服務器通信,等等。android
React 和 MobX 是一對強力組合。React 經過提供機制把應用狀態轉換爲可渲染組件樹並對其進行渲染。而MobX提供機制來存儲和更新應用狀態供 React 使用。webpack
對於應用開發中的常見問題,React 和 MobX 都提供了最優和獨特的解決方案。React 提供了優化UI渲染的機制, 這種機制就是經過使用虛擬DOM來減小昂貴的DOM變化的數量。MobX 提供了優化應用狀態與 React 組件同步的機制,這種機制就是使用響應式虛擬依賴狀態圖表,它只有在真正須要的時候才更新而且永遠保持是最新的。git
MobX 的核心概念很少。 下面的代碼片斷能夠在 codesandbox 示例中在線試用。程序員
Egghead.io 第1課: observable & observeres6
MobX 爲現有的數據結構(如對象,數組和類實例)添加了可觀察的功能。 經過使用 @observable 裝飾器(ES.Next)來給你的類屬性添加註解就能夠簡單地完成這一切。
1 import { observable } from "mobx"; 2 3 class Todo { 4 id = Math.random(); 5 @observable title = ""; 6 @observable finished = false; 7 }
使用 observable
很像把對象的屬性變成excel的單元格。 但和單元格不一樣的是,這些值不僅是原始值,還能夠是引用值,好比對象和數組。
若是你的環境不支持裝飾器語法,也沒必要擔憂。 你能夠點擊這裏查看如何進行設置。 或者你能夠直接跳過設置,由於 MobX 能夠經過 decorate 工具在不支持裝飾器語法的狀況加使用。 儘管如此,多數 MobX 用戶更喜歡裝飾器語法,由於它更簡潔。
例如,上面一段代碼的ES5版本應該是這樣:
1 import { decorate, observable } from "mobx"; 2
3 class Todo { 4 id = Math.random(); 5 title = ""; 6 finished = false; 7 } 8 decorate(Todo, { 9 title: observable, 10 finished: observable 11 })
Computed values(計算值)
使用 MobX, 你能夠定義在相關數據發生變化時自動更新的值。 經過@computed
裝飾器或者利用 (extend)Observable
時調用 的getter / setter 函數來進行使用。(固然,這裏也能夠再次使用 decorate
來替代 @
語法)。
1 class TodoList { 2 @observable todos = []; 3 @computed get unfinishedTodoCount() { 4 return this.todos.filter(todo => !todo.finished).length; 5 } 6 }
當添加了一個新的todo或者某個todo的 finished
屬性發生變化時,MobX 會確保 unfinishedTodoCount
自動更新。 像這樣的計算能夠相似於 MS Excel 這樣電子表格程序中的公式。每當只有在須要它們的時候,它們纔會自動更新。
Reactions 和計算值很像,但它不是產生一個新的值,而是會產生一些反作用,好比打印到控制檯、網絡請求、遞增地更新 React 組件樹以修補DOM、等等。 簡而言之,reactions 在 響應式編程和命令式編程之間創建溝通的橋樑。
Egghead.io 第1課: observable & observer
若是你用 React 的話,能夠把你的(無狀態函數)組件變成響應式組件,方法是在組件上添加 observer
函數/ 裝飾器. observer
由 mobx-react
包提供的。
1 import React, {Component} from 'react'; 2 import ReactDOM from 'react-dom'; 3 import {observer} from 'mobx-react'; 4
5 @observer 6 class TodoListView extends Component { 7 render() { 8 return <div>
9 <ul>
10 {this.props.todoList.todos.map(todo =>
11 <TodoView todo={todo} key={todo.id} />
12 )} 13 </ul>
14 Tasks left: {this.props.todoList.unfinishedTodoCount} 15 </div>
16 } 17 } 18
19 const TodoView = observer(({todo}) =>
20 <li>
21 <input 22 type="checkbox"
23 checked={todo.finished} 24 onClick={() => todo.finished = !todo.finished} 25 />{todo.title} 26 </li>
27 ) 28
29 const store = new TodoList(); 30 ReactDOM.render(<TodoListView todoList={store} />, document.getElementById('mount'));
observer
會將 React (函數)組件轉換爲它們須要渲染的數據的衍生。 使用 MobX 時沒有所謂的智能和無腦組件。 全部的組件都會以巧妙的方式進行渲染,而只須要一種簡單無腦的方式來定義它們。MobX 會確保組件老是在須要的時從新渲染,但僅此而已。因此上面例子中的 onClick
處理方法會強制對應的 TodoView
進行渲染,若是未完成任務的數量(unfinishedTodoCount)已經改變,它將致使 TodoListView
進行渲染。 但是,若是移除 Tasks left
這行代碼(或者將它放到另外一個組件中),當點擊 checkbox
的時候 TodoListView
就再也不從新渲染。你能夠在 JSFiddle 中本身動手來驗證這點。
使用autorun
、reaction
和 when
函數便可簡單的建立自定義 reactions,以知足你的具體場景。
例如,每當 unfinishedTodoCount
的數量發生變化時,下面的 autorun
會打印日誌消息:
autorun(() => {
console.log("Tasks left: " + todos.unfinishedTodoCount) })
爲何每次 unfinishedTodoCount
變化時都會打印一條新消息?答案就是下面這條經驗法則:
MobX 會對在執行跟蹤函數期間讀取的任何現有的可觀察屬性作出反應。
想深刻了解 MobX 是如何知道須要對哪一個可觀察屬性進行響應,請查閱 理解 MobX 對什麼有反應。
不一樣於 flux 系的一些框架,MobX 對於如何處理用戶事件是徹底開明的。
onClick
最後所有概括爲: 狀態應該以某種方式來更新。
當狀態更新後,MobX
會以一種高效且無障礙的方式處理好剩下的事情。像下面如此簡單的語句,已經足夠用來自動更新用戶界面了。
從技術上層面來說,並不須要觸發事件、調用分派程序或者相似的工做。歸根究底 React 組件只是狀態的華麗展現,而狀態的衍生由 MobX 來管理。
1 store.todos.push( 2 new Todo("Get Coffee"), 3 new Todo("Write simpler code") 4 ); 5 store.todos[0].finished = true;
儘管如此,MobX 仍是提供了 actions
這個可選的內置概念。 若是你如今就想要了解如何編寫 actions,請閱讀 Actions 章節。很簡單! 使用 actions
是有優點的: 它們能夠幫助你把代碼組織的更好,還能在狀態什麼時候何地應該被修改這個問題上幫助你作出明智的決定。
MobX 是狀態管理庫中侵入性最小的之一。這使得 MobX
的方法不但簡單,並且可擴展性也很是好:
使用 MobX 不須要使數據標準化。這使得庫十分適合那些異常複雜的領域模型(以 Mendix 爲例: 一個應用中有大約500個領域類)。
由於數據不須要標準化,因此 MobX 會自動跟蹤狀態和衍生之間的關係,你能夠免費得到參照完整性。渲染經過三級間接尋址訪問的數據?
沒有問題,MobX 會跟蹤它們,一旦其中一個引用發生了變化,就會從新渲染。做爲回報,陳年的老bug已不復存在。做爲一個程序員,你可能記不住修改的一些數據可能會影響到的某個角落裏看起來絕不相關的組件,但 MobX 不會。
正如上面所演示的,使用 MobX 修改狀態是很是簡單的。你只需簡單的寫出你的目的。MobX 會替你處理好剩下的事情。
MobX 構建應用中全部衍生的圖形,以找到保持最新狀態所需的從新計算的最少次數。「衍生一切」或許聽上去開銷很昂貴,但 MobX 構建虛擬衍生圖以保持衍生與狀態同步所需的重計算的數量最小化。
事實上,在 Mendix 測試 MobX 時咱們發現使用這個庫跟蹤代碼中的關係一般會更有效,而不是經過使用手寫事件或基於容器組件的「智能」選擇器來推送更改。
簡單來講,是由於 MobX 會在數據上創建更細粒度的「監聽器」,而不是經過程序來控制。
其次, MobX 看到衍生之間的因果關係,所以它能夠爲衍生排序,使得衍生不會運行屢次或引入缺陷。
想了解這是如何工做的? 請參見 深刻剖析 MobX。
MobX 使用原生 javascript 。因爲它的侵入性不強,它能夠和絕大部分 javascript 庫共同使用,而不須要特定的 MobX 風格庫。
因此你能夠繼續使用你的路由,數據獲取和工具庫,好比react-router
、 director
、 superagent
、 lodash
,等等。
出於一樣的緣由,你能夠在服務器端和客戶端使用它,也能夠在 react-native 這樣的同構應用中使用。
結論就是: 相比其它狀態管理解決方案,當使用 MobX 時一般只需學習更少的新概念。