在上一部分中,咱們研究瞭如何設置MobX狀態樹並使其可觀察。 有了這個,下一步就是開始對變化做出反應。 坦率地說,這就是有趣的開始!javascript
MobX保證只要您的響應數據圖發生變化,依賴於可觀察屬性的部分就會自動同步。 這意味着您如今能夠專一於對變化作出反應並引發的反作用,而不是擔憂數據同步。java
讓咱們深刻研究一下能夠引發反作用的各類方法。react
@action
做爲入口點默認狀況下,當您修改observable時,MobX將檢測並保持其餘依賴的可觀察對象同步。 這是同步發生的。 可是,有時您可能但願在同一方法中修改多個observable。 這可能會致使多個通知被觸發,甚至可能會下降您的應用速度。
segmentfault
更好的方法是action()
中包裝要調用的方法。 這會在您的方法周圍建立一個事務邊界,而且全部受影響的observable
將在您執行操做後保持同步。 請注意,此延遲通知僅適用於當前函數範圍中的observable
。 若是您具備修改更多可觀察對象的異步操做,則必須將它們包裝在runInAction()
中。異步
class Person { @observable firstName; @observable lastName; // 由於咱們在@action中包裝了此方法,因此只有在changeName()成功執行後,fullName纔會更改 @action changeName(first, last) { this.firstName = first; this.lastName = last; } @computed get fullName() { return `${this.firstName}, ${this.lastName}`; } } const p = new Person(); p.changeName('Pavan', 'Podila');
Actions
是改變Store的切入點。 經過使用Actions
,您能夠將多個observable更新爲原子操做。ide
儘量避免直接從外部操縱observable
並公開@action
方法爲你作這個改變。 實際上,能夠經過設置useStrict(true)
來強制執行此操做。
@autorun
觸發反作用MobX確保可觀察圖形始終保持一致。 但若是這個世界只是關於可觀察的東西,那就很差玩了。 咱們須要他們的同行:觀察者使事情變得有趣。函數
實際上,UI是mobx store
的美化觀察者。 使用mobx-react
,您將得到一個綁定庫,使您的React組件能夠觀察存儲並在存儲更改時自動呈現。this
可是,UI不是系統中惟一的觀察者。 您能夠向store
添加更多觀察者以執行各類有趣的事情。 一個很是基本的觀察者多是一個控制檯記錄器,它只是在可觀察的變化時將當前值記錄到控制檯。url
經過autorun
,咱們能夠很是輕鬆地設置這些觀察者。 最快的方法是提供autorun
功能。 MobX會自動跟蹤您在此函數中使用的任何可觀察對象。 每當它們改變時,你的功能都會從新執行(也就是自動運行)!spa
class Person { @observable firstName = 'None'; @observable lastName = 'None'; constructor() { // A simple console-logger autorun(()=>{ console.log(`Name changed: ${this.firstName}, ${this.lastName}`); }); // 這裏會致使autorun()運行 this.firstName = 'Mob'; // autorun()再一次運行 this.lastName = 'X'; } } // Will log: Name changed: None, None // Will log: Name changed: Mob, None // Will log: Name changed: Mob, X
正如您在上面的日誌中所看到的,自動運行將當即運行,而且每次跟蹤的可觀察量發生變化時也會運行。 若是您不想當即運行,而是僅在發生更改時運行,該怎麼辦? 請繼續閱讀。
reaction
觸發反作用與autorun
相比,reaction
提供了更細粒度的控制。 首先,它們不會當即運行並等待對跟蹤的可觀察量的第一次更改。 API也與autorun
略有不一樣。 在最簡單的版本中,您提供兩個輸入參數:
reaction(()=> data, data => { /* side effect */})
第一個函數(跟蹤函數 tracking function
)應該返回將用於跟蹤的數據。 而後將該數據傳遞給第二個函數(效果函數 effect function
)。 不跟蹤效果函數,您能夠在此處使用其餘可觀察對象。
默認狀況下,reaction
將不會在第一次運行,並將等待追蹤函數的變動。 只有當tracking function
返回的數據發生變化時,纔會執行反作用。 經過將原始自動運行分解爲tracking function
+effect function
,您能夠更好地控制實際致使反作用的內容。
import {reaction} from 'mobx'; class Router { @observable page = 'main'; setupNavigation() { reaction(()=>this.page, (page)=>{ switch(page) { case 'main': this.navigateToUrl('/'); break; case 'profile': this.navigateToUrl('/profile'); break; case 'admin': this.navigateToUrl('/admin'); break; } }); } navigateToUrl(url) { /* ... */ } }
在上面的示例中,我在加載「main」頁面時不須要導航。 一個reaction
使用的完美案例。 僅當路由器的頁面屬性發生更改時,纔會導航到特定URL。
以上是一個很是簡單的路由器,具備固定的頁面集。 您能夠經過向URL添加頁面地圖來使其更具可擴展性。 使用這種方法,路由(使用URL更改)會成爲更改Store某些屬性的反作用。
when
觸發一次性的反作用autorun
和reaction
是持續的反作用。 初始化應用程序時,您將建立此類反作用,並指望它們在應用程序的生命週期內運行。
我以前沒有提到的一件事是這兩個函數都返回一個處理器函數。 您能夠隨時調用該處理器函數並取消反作用。
const disposer = autorun(()=>{ /* side-effects based on tracked observables */ }); // .... At a later time disposer(); // Cancel the autorun
如今咱們構建的應用程序有各類用例。 您可能但願某些反作用僅在您到達應用程序中的某個點時運行。 此外,您可能但願這些反作用只運行一次,而後不再會運行。
讓咱們舉一個具體的例子:好比說,當用戶到達應用程序中的某個里程碑時,您但願向用戶顯示一條消息。 此里程碑僅對任何用戶發生一次,所以您不但願設置持續運行的反作用,如autorun
或reaction
。 如今是時候拿出when
這個API來完成這項工做了。
當拿出兩個參數時,就像reaction
同樣。 第一個(跟蹤器函數)應該返回一個布爾值。 當這變爲真時,它將運行效果函數,第二個參數爲when
。 最棒的部分是它會在運行後自動處理反作用。 所以,無需跟蹤處理器並手動調用它。
when(()=>this.reachedMilestone, ()=>{ this.showMessage({ title: 'Congratulations', message: 'You did it!' }); })
到目前爲止,咱們已經看到了各類技術來跟蹤對象圖上的變化,並對這些變化作出反應。 MobX提升了抽象級別,以便咱們能夠在更高級別進行思考,而沒必要擔憂跟蹤和對變化作出反應的意外複雜性。
咱們如今有了一個基礎,能夠構建依賴於域模型更改的強大系統。 經過將域模型以外的全部內容視爲反作用,咱們能夠提供視覺反饋(UI)並執行許多其餘活動,如監控,分析,日誌記錄等。