狀態管理庫 MobX 和 react

Pandaaa發表於2018-06-27

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 或者控制器什麼的.

引用:

10分鐘極速入門 MobX

sf @computed使用

react 官網

相關文章