observable
observable(value) @observable classProperty = value
// 若是 value 是ES6 Map的實例: 會返回一個新的 Observable Map。不僅關注某個特定entry的更改,並且對更改添加或刪除其餘entry時也作出反應。 // 若是 value 是數組,會返回一個 Observable Array。 // 若是 value 是沒有原型的對象或它的原型是 Object.prototype,那麼對象會被克隆而且全部的屬性都會被轉換成可觀察的。 // 若是 value 是有原型的對象,JavaSript 原始數據類型或者函數,值不會發生變化。若是你須要 Boxed Observable: 1, 顯式地調用 observable.box(value)
// observable.box(value, options?), // 使用 get() 方法能夠獲得盒子中的當前value,而使用 set() 方法能夠更新value // 使用 {deep: false} 選項會禁用新值被observable。
2, 在類定義時使用 @observable , // 是 的語法糖 3, 調用 decorate() 4, 在類中使用 extendObservable() 來引入屬性extendObservable(this, { property: value })
// 要想使用 @observable 裝飾器,首先要確保編譯器(babel 或者 typescript)中 裝飾器是啓用的。 // 默認狀況下將一個數據結構轉換成可觀察的是有感染性的,這意味着 observable 被自動應用於數據結構包含的任何值,或者未來會被該數據結構包含的值。這個行爲能夠經過使用 裝飾器 來更改
// 爲提供的對象建立一個克隆並將其全部的屬性轉換成 observable // 使用 {deep: false} 選項時只有屬性會轉換成 observable 引用,而值不會改變(這也適用於未來分配的任何值)。 observable.object(value, decorators?, options?) observable.array(value, options?) // 基於提供的值來建立一個新的 observable 數組。 observable.map(value, options?) // 基於提供的值來建立一個新的 observable 映射 建立動態的鍵集合而且須要能觀察到鍵的添加和移除,能夠自由使用任何鍵而無需侷限於字符串。
extendObservable(target, properties, decorators?, options?) // extendObservable 加強了現有的對象,不像 observable.object 是建立一個新對象 // 若是新的屬性不該該具有感染性,extendObservable(target, props, decorators?, {deep: false})
// 若是沒有傳入裝飾器,默認爲對任意鍵值對使用 observable.deep
,對 getters 使用 computed
。typescript
observable.deep: // 全部 observable 都使用的默認的裝飾器。它能夠把任何指定的、非原始數據類型的、非 observable 的值轉換成 observable。 observable.ref: // 禁用自動的 observable 轉換,只是建立一個 observable 引用。 observable.shallow: // 只能與集合組合使用。 將任何分配的集合轉換爲淺 observable (而不是深 observable)的集合。 換句話說, 集合中的值將不會自動變爲 observable。 computed: // 建立一個衍生屬性
:
// 與 相同,可是隻有當視圖產生的值與以前的值結構上有不一樣時,才通知它的觀察者 action: // 建立一個動做
:
// 建立一個動做, 並將 綁定到了實例
:
// 就像 , 但會忽略結構上等於當前值的新值
computed.structcomputedaction.boundthisobservable.structref
// @decorator 語法應用裝飾器 import {observable, action} from 'mobx'; class TaskStore { @observable.shallow tasks = [] @action addTask(task) { /* ... */ } }
// decorate() 傳入屬性裝飾器 import {observable, action} from 'mobx'; const taskStore = observable({ tasks: [], addTask(task) { /* ... */ } }, { tasks: observable.shallow, addTask: action })
// 使用 decorate 時,全部字段都應該指定 (畢竟,類裏的非 observable 字段可能會更多) class Person { name = "John" age = 42 showAge = false get labelText() { return this.showAge ? `${this.name} (age: ${this.age})` : this.name; } setAge(age) { this.age = age; } } decorate(Person, { name: observable, age: observable, showAge: observable, labelText: computed, setAge: action })
// 想要在單個屬性上應用多個裝飾器的話,能夠傳入一個裝飾器數組。多個裝飾器應用的順序是從右至左。 import { decorate, observable } from 'mobx' import { serializable, primitive } from 'serializr' import persist from 'mobx-persist' class Todo { id = Math.random(); title = ''; finished = false; } decorate(Todo, { title: [serializable(primitive), persist('object'), observable], finished: [serializable(primitive), observable] })
// @computed import {observable, computed} from "mobx"; class OrderLine { @observable price = 0; @observable amount = 1; constructor(price) { this.price = price; } @computed get total() { return this.price * this.amount; } }
// 使用 decorate 引入 import {decorate, observable, computed} from "mobx"; class OrderLine { price = 0; amount = 1; constructor(price) { this.price = price; } get total() { return this.price * this.amount; } } decorate(OrderLine, { price: observable, amount: observable, total: computed })
// observable.object 和 extendObservable 都會自動將 getter 屬性推導成計算屬性 const orderLine = observable.object({ price: 0, amount: 1, get total() { return this.price * this.amount } })
// 計算值的 setter // setters 不能用來直接改變計算屬性的值,能夠用來做「逆向」衍生。 const orderLine = observable.object({ price: 0, amount: 1, get total() { return this.price * this.amount }, set total(total) { // 從 total 中推導出 price this.price = total / this.amount } })
// 注意: 永遠在 getter 以後 定義 setter,一些 TypeScript 版本會知道聲明瞭兩個具備相同名稱的屬性。 class Foo { @observable length = 2; @computed get squared() { return this.length * this.length; } set squared(value) { this.length = Math.sqrt(value); } }
// computed 還能夠直接當作函數來調用, 可用於傳遞在box中計算值 import {observable, computed} from "mobx"; var name = observable.box("John"); var upperCaseName = computed(() => name.get().toUpperCase() // 使用 來獲取計算的當前值 );
// 來觀察值的改變 var disposer = upperCaseName.observe(change => console.log(change.newValue)); name.set("Dave"); // 輸出: 'DAVE'.get().observe(callback)
computed 接收的第二個選項參數對象選項 name: 字符串, 在 spy 和 MobX 開發者工具中使用的調試名稱 context: 在提供的表達式中使用的 this set: 要使用的setter函數。 沒有 setter 的話沒法爲計算值分配新值。 若是傳遞給 computed 的第二個參數是一個函數,那麼就把會這個函數做爲 setter equals: 默認值是 comparer.default 。它充當比較前一個值和後一個值的比較函數。 MobX 提供了三個內置 comparer (比較器) comparer.identity: 使用恆等 (===) 運算符來斷定兩個值是否相同。 comparer.default: 等同於 comparer.identity,但還認爲 NaN 等於 NaN comparer.structural: 執行深層結構比較以肯定兩個值是否相同。 requiresReaction: 對於很是關鍵的計算值,推薦設置成 true 。避免沒有跟蹤該值致使計算結果丟失。 keepAlive: 有無觀察者均保持計算。這很容易致使內存泄漏,由於它會致使此計算值使用的每一個 observable ,並將計算值保存在內存中!
// computed 錯誤處理 const x = observable.box(3) const y = observable.box(1) const divided = computed(() => { if (y.get() === 0) throw new Error("Division by zero") return x.get() / y.get() }) divided.get() // 返回 3 y.set(0) // OK divided.get() // 報錯: Division by zero divided.get() // 報錯: Division by zero y.set(2) divided.get() // 已恢復; 返回 1.5
// 建議在任何更改 observable 或者有反作用的函數上使用動做 // 動做還能提供很是有用的調試信息 action(fn) action(name, fn) @action classMethod() {} @action(name) classMethod () {} @action boundClassMethod = (args) => { body } @action(name) boundClassMethod = (args) => { body } @action.bound classMethod() {} // 它接收一個函數並返回具備一樣簽名的函數 // 用 transaction、untracked 和 allowStateChanges 包裹起來 // 默認是使用transaction, 動做會分批處理變化並只在(最外層的)動做完成後通知計算值和反應 // @action 裝飾器 不支持使用 setters
// 綁定的動做 // action.bound 能夠用來自動地將動做綁定到目標對象。 // 注意,與 action 不一樣的是,(@)action.bound 不須要一個name參數,名稱將始終基於動做綁定的屬性。 class Ticker { @observable tick = 0 @action.bound increment() { this.tick++ // 'this' 永遠都是正確的 } } const ticker = new Ticker() setInterval(ticker.increment, 1000)
runInAction(name?, thunk) // 工具函數,它接收代碼塊並在(異步的)動做中執行。這對於即時建立和執行動做很是有用