Mobx —— React狀態管理另一條路

Dominic_Ming發表於2017-12-25

閱讀時間:大概在 3 分鐘左右

本文章旨在介紹Mobx,不對其他狀態管理工具進行比較。

Redux 開啟了前端狀態管理大門,但是對於一些比較小的應用,使用 Redux 反而增加了開發複雜度,這時候,我會選擇使用 Mobx 來進行狀態管理。

Mobx 是什麼

Mobx是一個通過函式響應式程式設計,讓狀態管理更加簡單和容易擴充的庫。

它遵循一個最簡單的原則:

Anything that can be derived from the application state, should be derived. Automatically.

(所有能夠從應用狀態獲得的東西,都應該自動地被獲得)

他的原理非常簡潔:

mobx原理圖

  • Actions 是唯一允許修改state而且有其他副作用的函式
  • State 是一組可觀察的狀態,而且不應該包含冗餘的資料(例如不會被更新的狀態)
  • Computed Value 是一些純函式,返回通過 state 可以推匯出的值
  • Reactions 類似於 Computed Value,但是它允許副作用的產生(如更新 UI 狀態)

核心概念

Observable state

Mobx 為 JavaScript 本身已有的幾種資料結構都新增了可觀察的功能,也可以使用ES6的新特性,通過裝飾器來新增這些功能。

可觀察的物件:

import {observable, autorun, action} from "mobx";

var person = observable({
    // 可觀察的屬性
    name: "John",
    age: 42,
    showAge: false,

    // 計算後的屬性
    get labelText() {
        return this.showAge ? `${this.name} (age: ${this.age})` : this.name;
    },

    // action
    setAge: action(function(age) {
        this.age = age;
    })
});
// autorun 函式是來執行狀態後更新後引發的 reaction
autorun(() => console.log(person.labelText));

person.name = "Dave";
// 輸出: 'Dave'

複製程式碼

可觀察的陣列:

import {observable, autorun} from "mobx";

var todos = observable([
    { title: "Spoil tea", completed: true },
    { title: "Make coffee", completed: false }
]);

autorun(() => {
    console.log("Remaining:", todos
        .filter(todo => !todo.completed)
        .map(todo => todo.title)
        .join(", ")
    );
});

todos[0].completed = false;
// 輸出: 'Remaining: Spoil tea, Make coffee'

todos[2] = { title: 'Take a nap', completed: false };
// 輸出: 'Remaining: Spoil tea, Make coffee, Take a nap'

todos.shift();
// 輸出: 'Remaining: Make coffee, Take a nap'
複製程式碼

可觀察的Map:

import {observable} from "mobx";

const map = observable.map();

map.set("a", 100);

console.log(map.get("a"))
// 輸出: 100

map.observe(({name, newValue}) => console.log(name, "->", newValue))

map.set("b",100)
// 輸出: b -> 100
複製程式碼

原生的值和引用:

import {observable} from "mobx";

const cityName = observable("Vienna");

console.log(cityName.get());
// 輸出 'Vienna'

cityName.observe(function(change) {
    console.log(change.oldValue, "->", change.newValue);
});

cityName.set("Amsterdam");
// 輸出 'Vienna -> Amsterdam'
複製程式碼

Actions

狀態管理中有一個重要的概念,狀態應該以一種方式來更新。在Mobx之中,並不需要觸發事件、呼叫分發函式或者類似的動作,狀態的基本相應派發由 Mobx 本身來負責。

但是讓Mobx全盤接管顯然限制了可擴充性和可用性,所以Mobx提供了Actions來使用。Actions應該永遠只對修改狀態的函式使用動作。建議對任何修改 observables 或具有副作用的函式使用 (@)action 。 結合開發者工具的話,動作還能提供非常有用的除錯資訊。

Reactions

Reactions 和計算值很像,但它不是產生一個新的值,而是會產生一些副作用,比如列印到控制檯、網路請求、遞增地更新 React 元件樹以修補DOM、等等。 簡而言之,reactions 在 響應式程式設計和指令式程式設計之間建立溝通的橋樑。

在 React 裡使用 Mobx

談了那麼多概念那麼怎麼在 React 裡面使用呢。

observer 函式/裝飾器可以用來將 React 元件轉變成響應式元件。 它用 mobx.autorun 包裝了元件的 render 函式以確保任何元件渲染中使用的資料變化時都可以強制重新整理元件。 observer 是由單獨的 mobx-react 包提供的。

import {observer} from "mobx-react";

var timerData = observable({
    secondsPassed: 0
});

setInterval(() => {
    timerData.secondsPassed++;
}, 1000);

@observer class Timer extends React.Component {
    render() {
        return (<span>Seconds passed: { this.props.timerData.secondsPassed } </span> )
    }
};

React.render(<Timer timerData={timerData} />, document.body);
複製程式碼

mobx 使用的時候,確保讓observer滲透到最深處的元件,因為狀態是向下傳遞的,如果原子元件沒有加入Mobx的觀察,那麼就可能就沒有效果。

擴充閱讀

官方文件

十分鐘互動式的 MobX + React 教程

訪談: 狀態管理很容易 - React Amsterdam 2016 開發者大會 (幻燈片)

相關文章