MobX
- MobX 是一個簡單、方便擴充套件、久經考驗的狀態管理解決方案
基本概念
-
MobX 是一個獨立的元件,可以配合各種框架使用,由於專案中需要使用 react & MobX。下面來詳細瞭解一下
-
State 是每一個應用程式的核心部分,而使用一個不合規範的 State 則是讓你的應用充滿 bug 和失控的不二法門,或者就是區域性變數環繞,讓你的 state 失去了同步。有很多框架試圖解決這個問題,比如使用不可變的 state,但是這樣以來又帶來了新的問題,比如資料必須規格化,完整性約束失效等等。
MobX 功能
-
MobX 讓整個事情又變簡單了:它不允許產生失控的 state。它的理念也很簡單:所有可以從 state 中派生的事物,都會自動的派生。
-
demo
class TodoStore {
todos = [];
get completedTodosCount() {
return this.todos.filter(
todo => todo.completed === true
).length;
}
report() {
if (this.todos.length === 0)
return "<none>";
return `Next todo: "${this.todos[0].task}". ` +
`Progress: ${this.completedTodosCount}/${this.todos.length}`;
}
addTodo(task) {
this.todos.push({
task: task,
completed: false,
assignee: null
});
}
}
const todoStore = new TodoStore();
複製程式碼
當我們去建立一個
todoStore
,他擁有一個todos
集合,現在我們往這個todoStore
裡新增一些東西,為了明顯起見,就呼叫todoStore.report
todoStore.addTodo("read MobX tutorial");
console.log(todoStore.report());
todoStore.addTodo("try MobX");
console.log(todoStore.report());
todoStore.todos[0].completed = true;
console.log(todoStore.report());
todoStore.todos[1].task = "try MobX in own project";
console.log(todoStore.report());
todoStore.todos[0].task = "grok MobX tutorial";
console.log(todoStore.report());
複製程式碼
- 太巧了,這就是 MobX 能為你做的事情。自動執行只在 state 改變的時候觸發,就好像 Excel 中的圖表只在單元格資料改變時更新一樣。為了達到這個目標,
TodoStore
必須成為可觀測的(observable
)才行,讓我們來改一些程式碼。
observable & computed
同時,completedTodosCount 屬性應該被自動派生,使用 @observable 和 @computed 裝飾器來做這些事情:
class ObservableTodoStore {
@observable todos = [];
@observable pendingRequests = 0;
constructor() {
mobx.autorun(() => console.log(this.report));
}
@computed get completedTodosCount() {
return this.todos.filter(
todo => todo.completed === true
).length;
}
@computed get report() {
if (this.todos.length === 0)
return "<none>";
return `Next todo: "${this.todos[0].task}". ` +
`Progress: ${this.completedTodosCount}/${this.todos.length}`;
}
addTodo(task) {
this.todos.push({
task: task,
completed: false,
assignee: null
});
}
}
const observableTodoStore = new ObservableTodoStore();
複製程式碼
- 在這個構造器中,我們使用
autorun
包裹了一個打出report
的小函式。Autorun
裡的東西首先會執行一次,然後當其中的函式有observable
的資料發生變化時,會再次執行。 這裡我們使用了todos
屬性,每次todos
變化了我們就列印出新的東西。 - 測試一下
observableTodoStore.addTodo("read MobX tutorial");
observableTodoStore.addTodo("try MobX");
observableTodoStore.todos[0].completed = true;
observableTodoStore.todos[1].task = "try MobX in own project";
observableTodoStore.todos[0].task = "grok MobX tutorial";
複製程式碼
舉個栗子(sf 的一個問題有感)
- 對於單個物件,我可以使用computed通過計算獲得一些屬性,比如
@observable good = {
number: 2,
price: 3
}
@computed get totalPrice() {
return this.good.number * this.good.price;
}
// 陣列
@observable goodsList = [{
number: 2,
price: 3
},{
number: 2,
price: 3
}]
複製程式碼
-
問題?
- 這種情況我如何通過computed獲得陣列某個元素的計算屬性呢,還是隻能在改變number的函式中手動去更改,但是我陣列的物件中並沒有一個totalPrice的屬性,每次把單個good push到goodsList中去還要給good新增一個totalPrice屬性豈不是很麻煩
-
解決方案
- 把
good
弄成一個單獨的model檔案
- 把
export default class Good{
@observable number;
@observable price;
constructor(number, price) {
this.number = number;
this.price = price;
}
@computed
get totalPrice() {
return this.number * this.price
}
}
複製程式碼
-
- 然後在goodList檔案中
- 這樣就實現了自動計算, 訪問的時候類似 this.props.goodList[0].totalPrice
@action
addGood(...args) {
this.todos.push(new Good(...args));
}
複製程式碼
- 未完待續...
總結
- 最後總結一些:
@observale
修飾器或者 observable 函式讓物件可以被追蹤;@computed
修飾器創造了自動運算的表示式;autorun
函式讓依靠 observable 的函式自動執行,這個用來寫 log,發請求很不錯;@observer
修飾器讓React
組建自動起來,它會自動更新,即便是在一個很大的程式裡也會工作的很好;
MobX
不是一個狀態容器
很多人把 MobX
當作另外一個 Redux
,但是它僅僅是一個庫,不是一個什麼架構。上面的例子還是需要程式設計師自己去組織邏輯和 store
或者控制器什麼的.