- 蘇格團隊
- 做者:Demian
本文是筆者在看了 frontendmaster 的狀態管理課程以後,對 mobx 進行的初步學習的總結。html
mobx 是社區內使用的較爲常見的一種狀態管理庫,mobx 官網稱其vue
經過透明的函數響應式編程(transparently applying functional reactive programming - TFRP)使得狀態管理變得簡單和可擴展react
mobx 主要有如下幾個核心特性:git
如下介紹將結合部分 mobx 代碼,代碼地址: 示例代碼github
詳細代碼以下:編程
// html
<div id="console" />;
// js
const { computed, observable, autorun } = mobx;
class Person {
@observable firstName;
@observable secondName;
constructor(firstName, secondName) {
this.firstName = firstName;
this.secondName = secondName;
}
@computed get fullName() {
return this.firstName + ' ' + this.secondName;
}
}
const wdz = new Person('Demian', 'Wang');
const greet = observable.box('good morning! ');
const render = () => {
document.getElementById('console').innerText = greet + wdz.fullName;
};
// 動態更新dom內容
autorun(render);
複製代碼
此時網頁 ui 爲:redux
首先介紹一下計算屬性。在上述代碼中 fullName 就是計算屬性。相信用過 vue 的對這個很熟悉。當咱們在命令行手動修改 wdz 的 firstName 時,wdz 的 fullName 會自動更新babel
此時網頁 ui 也發生了實時的變化:app
可見,computed 屬性能夠響應 observable 屬性的變化。frontend
值得一提的是,在 react 的 render 函數中,若是存在不少 props 的計算的話,可使用 get 語法的形式將這部分邏輯抽離:
get fullName() {
return this.props.firstName + this.props.secondName;
}
render() {
return <div>{this.fullName}</div>
}
複製代碼
這裏的 fullName 和可計算屬性相似,依據傳入的 props 屬性動態變化。
經過在類屬性前加上@observable,爲該屬性添加了可觀察功能。
import { observable } from 'mobx';
class Person {
@observable firstName;
constructor(firstName) {
this.firstName = firstName;
}
}
複製代碼
使用裝飾器語法很簡潔的使得 name 擁有了可觀察的功能。
那麼 Observable 有什麼做用呢?
見如下代碼:
const greet = observable.box('good morning! ');
複製代碼
咱們爲 greet 返回一個 observable 包裝過的值,首先咱們試着直接改變 greet 的值
可是,此時網頁 ui 沒有實時變化:
可見,原始類型在包裝過以後, 直接改變引用值不能觸發頁面動態更新,感興趣的讀者能夠點擊上面的連接打印出 greet 的屬性,就能很直觀的認識到 observable 的做用。如下是簡化版的 observable:
// 簡單的observable
const observable = value => {
return {
value,
get() {
console.log('get', this.value);
return this.value;
},
set(newValue) {
console.log('set', newValue);
// 向全局通知該數據更新
report(this.value, newValue);
this.value = newValue;
}
};
};
// reactive代碼
eventEmitter.on('report', (oldValue, newValue) => {
console.log(oldValue, '===>', newValue);
});
// 通知給全局
const report = (oldValue, newValue) => {
eventEmitter.emit('report', oldValue, newValue);
};
複製代碼
主要是使用 value 值存儲原始類型,使用 get 獲取 value 值,使用 set 更新 value 值。值得注意的是,在更新數據之前,set 方法會根據必定的配置,選擇是否向全局發送更新事件,相應的一些 computed 的屬性會接收到該事件。
const render = () => {
document.getElementById('console').innerText = greet + wdz.fullName;
};
// 動態更新dom內容
autorun(render);
複製代碼
當 observable 數據變化後,頁面會自動更新 ui。
注:因爲 create-react-app 建立的項目默認不能使用裝飾器語法,因此筆者暴力的 eject 並安裝了相應的 babel 配置。
如下是 todoList 的項目結構:
最終實現效果: 項目地址: todolist當咱們使用 mobx 維護狀態時,store 不像 redux 那樣是全局惟一的,咱們能夠細粒度地維護一個個數據模型。在中小型的項目中,mobx 的 store 輕便簡潔,使用起來很順滑。
項目中用到的 mobx 特性:
主要維護 todolist 的基本狀態:待辦列表 todolist、新建待辦的內容 itemContent 和當前篩選類型 filterType
根據當前篩選器的類型,返回對應的 todoList。
篩選器狀態變化後,響應式地打印出當前篩選器的狀態。
點擊篩選器後的狀態切換和異步事件。這裏須要使用 runInAction 包裝異步函數,這樣才能夠完成響應式的更新數據。
二者都是優秀的狀態管理工具,均可以幫助開發者完成業務開發。因此拋開業務場景談論工具優劣是無心義的,筆者這裏只是簡單列出二者的區別。
筆者只是介紹了 mobx 的冰山一角,其做爲一種響應式的狀態管理庫,在中小型項目中有着高效率的表現。響應式的寫法、細粒度的 store 管理都體現了 mobx 的靈活性。