高效的Mobx模式(Part 2 - 掌握數據變動方法)

在上一部分中,咱們研究瞭如何設置MobX狀態樹並使其可觀察。 有了這個,下一步就是開始對變化做出反應。 坦率地說,這就是有趣的開始!javascript

MobX保證只要您的響應數據圖發生變化,依賴於可觀察屬性的部分就會自動同步。 這意味着您如今能夠專一於對變化作出反應並引發的反作用,而不是擔憂數據同步。java

讓咱們深刻研究一下能夠引發反作用的各類方法。react

使用@action做爲入口點

默認狀況下,當您修改observable時,MobX將檢測並保持其餘依賴的可觀察對象同步。 這是同步發生的。 可是,有時您可能但願在同一方法中修改多個observable。 這可能會致使多個通知被觸發,甚至可能會下降您的應用速度。
actionsegmentfault

更好的方法是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觸發一次性的反作用

autorunreaction是持續的反作用。 初始化應用程序時,您將建立此類反作用,並指望它們在應用程序的生命週期內運行。

我以前沒有提到的一件事是這兩個函數都返回一個處理器函數。 您能夠隨時調用該處理器函數並取消反作用。

const disposer = autorun(()=>{ 
    /* side-effects based on tracked observables */ 
});

// .... At a later time
disposer(); // Cancel the autorun

如今咱們構建的應用程序有各類用例。 您可能但願某些反作用僅在您到達應用程序中的某個點時運行。 此外,您可能但願這些反作用只運行一次,而後不再會運行。

讓咱們舉一個具體的例子:好比說,當用戶到達應用程序中的某個里程碑時,您但願向用戶顯示一條消息。 此里程碑僅對任何用戶發生一次,所以您不但願設置持續運行的反作用,如autorunreaction。 如今是時候拿出when 這個API來完成這項工做了。

當拿出兩個參數時,就像reaction同樣。 第一個(跟蹤器函數)應該返回一個布爾值。 當這變爲真時,它將運行效果函數,第二個參數爲when。 最棒的部分是它會在運行後自動處理反作用。 所以,無需跟蹤處理器並手動調用它。

when(()=>this.reachedMilestone, ()=>{
    this.showMessage({ 
        title: 'Congratulations', 
        message: 'You did it!'
    });
})


到目前爲止,咱們已經看到了各類技術來跟蹤對象圖上的變化,並對這些變化作出反應。 MobX提升了抽象級別,以便咱們能夠在更高級別進行思考,而沒必要擔憂跟蹤和對變化作出反應的意外複雜性。

咱們如今有了一個基礎,能夠構建依賴於域模型更改的強大系統。 經過將域模型以外的全部內容視爲反作用,咱們能夠提供視覺反饋(UI)並執行許多其餘活動,如監控,分析,日誌記錄等。

相關文章
相關標籤/搜索