成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

高效的Mobx模式(Part 3 高階應(yīng)用實例)

eccozhou / 2940人閱讀

摘要:當樹變異時,連接的部分將作出反應(yīng)并更新以反映變化。接下來,我們必須對這些行動狀態(tài)發(fā)生的變化作出反應(yīng)。這可用于將工作流轉(zhuǎn)換為其他狀態(tài)。將其視為產(chǎn)生價值的可觀察物。構(gòu)建可觀察數(shù)據(jù)掌握數(shù)據(jù)變更方法高階應(yīng)用實例

前兩部分側(cè)重于MobX的基本構(gòu)建塊。 有了這些塊,我們現(xiàn)在可以通過MobX的角度開始解決一些真實場景。 這篇文章將是一系列應(yīng)用我們迄今為止所見概念的例子。

當然,這不是一個詳盡的清單,但應(yīng)該讓你體會到應(yīng)用MobX角度所需要的心理轉(zhuǎn)變。 所有示例都是在沒有@decorator (裝飾器)語法的情況下創(chuàng)建的。 這允許您在Chrome控制臺,Node REPL或支持臨時文件的WebStorm等IDE中進行嘗試。

改變思維方式

當您學(xué)習(xí)某些庫或框架背后的理論并嘗試將其應(yīng)用于您自己的問題時,您最初可能會畫一個空白。 它發(fā)生在像我這樣的普通人身上,甚至是最好的人。 寫作界稱之為“Writer’s block”,而在藝術(shù)家的世界里,它就是“Painter’s block”

我們需要的是從簡單到復(fù)雜的例子來塑造我們的思維方式。 只有看到應(yīng)用程序,我們才能開始想象解決我們自己的問題的方法。

對于MobX,它首先要了解您有一個reactive object-graph這一事實。 樹的某些部分可能依賴于其他部分。 當樹變異時,連接的部分將作出反應(yīng)并更新以反映變化。

思維方式的轉(zhuǎn)變是將手頭的系統(tǒng)設(shè)想為一組反應(yīng)性變動 + 一組相應(yīng)的結(jié)果。

效果可以是由于反應(yīng)性變化而產(chǎn)生輸出的任何事物。 讓我們探索各種現(xiàn)實世界的例子,看看我們?nèi)绾斡肕obX建模和表達它們。

Example 1: 發(fā)送重要操作的分析

問題:我們在應(yīng)用程序中有一些必須記錄到服務(wù)器的一次性操作。 我們希望跟蹤執(zhí)行這些操作的時間并發(fā)送分析。

1、是對建立狀態(tài)模型。 我們的行為是有限的,我們只關(guān)心它執(zhí)行一次。 我們可以使用動作方法的名稱建立對應(yīng)的布爾值類型狀態(tài), 這是我們可觀察到的狀態(tài)。

const actionMap = observable({
    login: false,
    logout: false,
    forgotPassword: false,
    changePassword: false,
    loginFailed: false
});

2、接下來,我們必須對這些行動狀態(tài)發(fā)生的變化作出反應(yīng)。 因為它們只在生命周期中發(fā)生過一次,所以我們不會使用長期運行的效果,如autorun()reaction()。 我們也不希望這些效果在執(zhí)行后存在。 好吧,這給我們留下了一個選擇:....
....
....

when
Object.keys(actionMap)
    .forEach(key => {
        when(
            () => actionMap[key],
            () => reportAnalyticsForAction(key)
        );
    });

function reportAnalyticsForAction(actionName) {
    console.log("Reporting: ", actionName);

    /* ... JSON API Request ... */
}

在上面的代碼中,我們只是循環(huán)遍歷actionMap中的鍵并為每個鍵設(shè)置when()副作用。 當tracker-function(第一個參數(shù))返回true時,副作用將運行。 運行效果函數(shù)(第二個參數(shù))后,when()將自動處理。 因此,沒有從應(yīng)用程序發(fā)送多個報告的問題!

3、我們還需要一個MobX動作來改變可觀察狀態(tài)。 請記?。河肋h不要直接修改您的observable。 始終通過action來做到這一點。
對上面的例子來說,如下:

const markActionComplete = action((name) => {
    actionMap[name] = true;
});

markActionComplete("login");
markActionComplete("logout");

markActionComplete("login");

// [LOG] Reporting:  login
// [LOG] Reporting:  logout

請注意,即使我將登錄操作標記觸發(fā)兩次,也沒有發(fā)送日志報告。 完美,這正是我們需要的結(jié)果。
它有兩個原因:

login標記已經(jīng)為true,因此值沒有變化

此外,when()副作用已被觸發(fā)執(zhí)行,因此不再發(fā)生追蹤。

Example 2: 作為工作流程的一部分啟動操作

問題:我們有一個由幾個狀態(tài)組成的工作流程。 每個狀態(tài)都映射到某些任務(wù),這些任務(wù)在工作流到達該狀態(tài)時執(zhí)行。

1、從上面的描述中可以看出,唯一可觀察的值是工作流的狀態(tài)。 需要為每個狀態(tài)運行的任務(wù)可以存儲為簡單映射。 有了這個,我們可以模擬我們的工作流程:

class Workflow {
    constructor(taskMap) {
        this.taskMap = taskMap;
        this.state = observable({
            previous: null,
            next: null
        });

        this.transitionTo = action((name) => {
            this.state.previous = this.state.next;
            this.state.next = name;
        });

        this.monitorWorkflow();
    }

    monitorWorkflow() {
        /* ... */
    }
}

// Usage
const workflow = new Workflow({
    start() {
        console.log("Running START");
    },

    process(){
        console.log("Running PROCESS");
    },

    approve() {
        console.log("Running APPROVE");
    },

    finalize(workflow) {
        console.log("Running FINALIZE");

        setTimeout(()=>{
            workflow.transitionTo("end");
        }, 500);
    },

    end() {
        console.log("Running END");
    }
});

請注意,我們正在存儲一個名為state的實例變量,該變量跟蹤工作流的當前和先前狀態(tài)。 我們還傳遞state->task的映射,存儲為taskMap

2、現(xiàn)在有趣的部分是關(guān)于監(jiān)控工作流程。 在這種情況下,我們沒有像前一個例子那樣的一次性操作。 工作流通常是長時間運行的,可能在應(yīng)用程序的生命周期內(nèi)。 這需要autorunreaction()。

只有在轉(zhuǎn)換到狀態(tài)時才會執(zhí)行狀態(tài)任務(wù)。 因此我們需要等待對this.state.next進行更改才能運行任何副作用(任務(wù))。 等待更改表示使用reaction()因為它僅在跟蹤的可觀察值更改值時才會運行。 所以我們的監(jiān)控代碼如下所示:

class Workflow {
    /* ... */
    monitorWorkflow() {
        reaction(
            () => this.state.next,
            (nextState) => {
                const task = this.taskMap[nextState];
                if (task) {
                    task(this);
                }
            }
        )
    }
}

reaction()第一個參數(shù)是跟蹤函數(shù),在這種情況下只返回this.state.next。 當跟蹤功能的返回值改變時,它將觸發(fā)效果功能。 效果函數(shù)查看當前狀態(tài),從this.taskMap查找任務(wù)并簡單地調(diào)用它。

請注意,我們還將工作流的實例傳遞給任務(wù)。 這可用于將工作流轉(zhuǎn)換為其他狀態(tài)。

workflow.transitionTo("start");

workflow.transitionTo("finalize");

// [LOG] Running START
// [LOG] Running FINALIZE
/* ... after 500ms ... */
// [LOG] Running END

有趣的是,這種存儲一個簡單的observable的技術(shù),比如this.state.next和使用reaction()來觸發(fā)副作用,也可以用于:

通過react-router進行路由

在演示應(yīng)用程序中導(dǎo)航

基于模式在不同視圖之間切換

Example 3: 輸入更改時執(zhí)行表單驗證

問題:這是一個經(jīng)典的Web表單用例,您需要驗證一堆輸入。 如果有效,允許提交表單。

1、讓我們用一個簡單的表單數(shù)據(jù)類對其進行建模,其字段必須經(jīng)過驗證。

class FormData {
    constructor() {
        extendObservable(this, {
            firstName: "",
            lastName: "",
            email: "",
            acceptTerms: false,

            errors: {},

            get valid() { // this becomes a computed() property
                return (this.errors === null);
            }
        });

        this.setupValidation(); // We will look at this below
    }
}

extendObservable()API是我們以前從未見過的。 通過在我們的類實例(this)上應(yīng)用它,我們得到一個ES5相當于創(chuàng)建一個@observable類屬性。

class FormData {
    @observable firstName = "";
    /* ... */
}

2、接下來,我們需要監(jiān)視這些字段何時發(fā)生變化并運行一些驗證邏輯。 如果驗證通過,我們可以將實體標記為有效并允許提交。 使用計算屬性跟蹤有效性本身:有效。

由于驗證邏輯需要在FormData的生命周期內(nèi)運行,因此我們將使用autorun()。 我們也可以使用reaction()但我們想立即運行驗證而不是等待第一次更改。

class FormData {
    setupValidation() {
        autorun(() => {
            // Dereferencing observables for tracking
            const {firstName, lastName, email, acceptTerms} = this;
            const props = {
                firstName,
                lastName,
                email,
                acceptTerms
            };

            this.runValidation(props, {/* ... */})
                .then(result => {
                    this.errors = result;
                })
        });
    }

    runValidation(propertyMap, rules) {
        return new Promise((resolve) => {
            const {firstName, lastName, email, acceptTerms} = propertyMap;

            const isValid = (firstName !== "" && lastName !== "" && email !== "" && acceptTerms === true);
            resolve(isValid ? null : {/* ... map of errors ... */});
        });
    }

}

在上面的代碼中,autorun()將在跟蹤的observables發(fā)生更改時自動觸發(fā)。 請注意,要使MobX正確跟蹤您的observable,您必須使用解除引用。

runValidation()是一個異步調(diào)用,這就是我們返回一個promise的原因。 在上面的示例中,它并不重要,但在現(xiàn)實世界中,您可能會調(diào)用服務(wù)器進行一些特殊驗證。 當結(jié)果返回時,我們將設(shè)置錯誤observable,這將反過來更新有效的計算屬性。

如果你有一個耗時較大的驗證邏輯,你甚至可以使用autorunAsync(),它有一個參數(shù)可以延遲執(zhí)行去抖動。

2、好吧,讓我們的代碼付諸行動。 我們將設(shè)置一個簡單的控制臺記錄器(通過autorun())并跟蹤有效的計算屬性。

const instance = new FormData();

// Simple console logger
autorun(() => {
    // input的每一次輸入,結(jié)果都會觸發(fā)error變更,autorun隨即執(zhí)行
    const validation = instance.errors;

    console.log(`Valid = ${instance.valid}`);
    if (instance.valid) {
        console.log("--- Form Submitted ---");
    }

});

// Let"s change the fields
instance.firstName = "Pavan";
instance.lastName = "Podila";
instance.email = "[email protected]";
instance.acceptTerms = true;

//     輸出日志如下
//     Valid = false
//    Valid = false
//    Valid = false
//    Valid = false
//    Valid = false
//    Valid = true
//    --- Form Submitted ---

由于autonrun()立即運行,您將在開頭看到兩個額外的日志,一個用于instance.errors,一個用于instance.valid,第1-2行。 其余四行(3-6)用于現(xiàn)場的每次更改。

每個字段更改都會觸發(fā)runValidation(),每次都會在內(nèi)部返回一個新的錯誤對象。 這會導(dǎo)致instance.errors的引用發(fā)生更改,然后觸發(fā)我們的autorun()以記錄有效標志。 最后,當我們設(shè)置了所有字段時,instance.errors變?yōu)閚ull(再次更改引用)并記錄最終的“Valid = true”。

4、簡而言之,我們通過使表單字段可觀察來進行表單驗證。 我們還添加了額外的errors屬性和有效的計算屬性來跟蹤有效性。 autorun()通過將所有內(nèi)容捆綁在一起來節(jié)省時間。

Example 4: 跟蹤所有已注冊的組件是否已加載

問題: 我們有一組已注冊的組件,我們希望在所有組件都加載后跟蹤。 每個組件都將公開一個返回 promise的load()方法。 如果promise解析,我們將組件標記為已加載。 如果它拒絕,我們將其標記為失敗。 當所有這些都完成加載時,我們將報告整個集是否已加載或失敗。

1、我們先來看看我們正在處理的組件。 我們正在創(chuàng)建一組隨機報告其負載狀態(tài)的組件。 另請注意,有些是異步的。

const components = [
    {
        name: "first",
        load() {
            return new Promise((resolve, reject) => {
                Math.random() > 0.5 ? resolve(true) : reject(false);
            });
        }
    },
    {
        name: "second",
        load() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    Math.random() > 0.5 ? resolve(true) : reject(false);
                }, 1000);
            });
        }
    },
    {
        name: "third",
        load() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    Math.random() > 0.25 ? resolve(true) : reject(false);
                }, 500);
            });
        }
    },
];

2、下一步是為Tracker設(shè)計可觀察狀態(tài)。 組件的load()不會按特定順序完成。 所以我們需要一個可觀察的數(shù)組來存儲每個組件的加載狀態(tài)。 我們還將跟蹤每個組件的報告狀態(tài)。

當所有組件都已報告時,我們可以通知組件集的最終加載狀態(tài)。 以下代碼設(shè)置了可觀察量。

class Tracker {
    constructor(components) {
        this.components = components;

        extendObservable(this, {

            // Create an observable array of state objects,
            // one per component
            states: components.map(({name}) => {
                return {
                    name,
                    reported: false,
                    loaded: undefined
                };
            }),

            // computed property that derives if all components have reported
            get reported() {
                return this.states.reduce((flag, state) => {
                    return flag && state.reported;
                }, true);
            },

            // computed property that derives the final loaded state 
            // of all components
            get loaded() {
                return this.states.reduce((flag, state) => {
                    return flag && !!state.loaded;
                }, true);
            },

            // An action method to mark reported + loaded
            mark: action((name, loaded) => {
                const state = this.states.find(state => state.name === name);

                state.reported = true;
                state.loaded = loaded;
            })

        });

    }
}

我們回到使用extendObservable()來設(shè)置我們的可觀察狀態(tài)。 reportedload的計算屬性跟蹤組件完成其加載的時間。 mark()是我們改變可觀察狀態(tài)的動作方法。

順便說一句,建議在需要從您的observables派生值的任何地方使用computed。 將其視為產(chǎn)生價值的可觀察物。 計算值也會被緩存,從而提高性能。 另一方面,autorunreaction不會產(chǎn)生價值。 相反,它們提供了創(chuàng)建副作用的命令層。

3、為了啟動跟蹤,我們將在Tracker上創(chuàng)建一個track()方法。 這將觸發(fā)每個組件的load()并等待返回的Promise解析/拒絕。 基于此,它將標記組件的負載狀態(tài)。

when()所有組件都已reported時,跟蹤器可以報告最終加載的狀態(tài)。 我們在這里使用,因為我們正在等待條件變?yōu)檎妫╰his.reported)。 報告的副作用只需要發(fā)生一次,非常適合when()。

以下代碼負責(zé)以上事項:

class Tracker {
    /* ... */ 
    track(done) {
        when(
            () => this.reported,
            () => {
                done(this.loaded);
            }
        );

        this.components.forEach(({name, load}) => {
            load()
                .then(() => {
                    this.mark(name, true);
                })
                .catch(() => {
                    this.mark(name, false);
                });
        });
    }

    setupLogger() {
        autorun(() => {
            const loaded = this.states.map(({name, loaded}) => {
                return `${name}: ${loaded}`;
            });

            console.log(loaded.join(", "));
        });
    }
}

setupLogger()實際上不是解決方案的一部分,但用于記錄報告。 這是了解我們的解決方案是否有效的好方法。

4、現(xiàn)在我們來測試一下:

const t = new Tracker(components);
t.setupLogger();
t.track((loaded) => {
    console.log("All Components Loaded = ", loaded);
});

// first: undefined, second: undefined, third: undefined
// first: true, second: undefined, third: undefined
// first: true, second: undefined, third: true
// All Components Loaded =  false
// first: true, second: false, third: true

記錄的輸出顯示其按預(yù)期工作。 在組件報告時,我們記錄每個組件的當前加載狀態(tài)。 當所有人報告時,this.reported變?yōu)閠rue,我們看到“All Components Loaded”消息。

希望上面的一些例子讓你體會到在MobX中的思考。

設(shè)計可觀察狀態(tài)

設(shè)置變異動作方法以更改可觀察狀態(tài)

放入跟蹤功能(when,autorun,reaction)以響應(yīng)可觀察狀態(tài)的變化

上述公式應(yīng)該適用于需要在發(fā)生變化后跟蹤某些內(nèi)容的復(fù)雜場景,這可能導(dǎo)致重復(fù)1-3步驟。

Part 1 - 構(gòu)建可觀察數(shù)據(jù)

Part 2 - 掌握數(shù)據(jù)變更方法

Part 3 - 高階應(yīng)用實例

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/97505.html

相關(guān)文章

  • 高效Mobx模式Part 1 - 構(gòu)建可觀察數(shù)據(jù))

    摘要:高效的模式提供了一種簡單而強大的方法來管理客戶端狀態(tài)。允許屬性本身可觀察,但不允許其任何子節(jié)點。默認情況下,僅將引用更改視為更改。構(gòu)建可觀察數(shù)據(jù)掌握數(shù)據(jù)變更方法高階應(yīng)用實例 起因 很早之前看到的一篇關(guān)于mobx的文章,之前記得是有人翻譯過的,但是怎么找都找不到,故花了點時間通過自己那半桶水的英文水平,加上Google翻譯一下,對于初學(xué)者,以及mobx的開發(fā)者提供些許幫助。 這里針對已經(jīng)...

    trigkit4 評論0 收藏0
  • 高效Mobx模式Part 2 - 掌握數(shù)據(jù)變更方法)

    摘要:有了這個,下一步就是開始對變化作出反應(yīng)。請注意,此延遲通知僅適用于當前函數(shù)范圍中的。最快的方法是提供功能。只有當返回的數(shù)據(jù)發(fā)生變化時,才會執(zhí)行副作用。最棒的部分是它會在運行后自動處理副作用。構(gòu)建可觀察數(shù)據(jù)掌握數(shù)據(jù)變更方法高階應(yīng)用實例 在上一部分中,我們研究了如何設(shè)置MobX狀態(tài)樹并使其可觀察。 有了這個,下一步就是開始對變化作出反應(yīng)。 坦率地說,這就是有趣的開始! MobX保證只要您的...

    xinhaip 評論0 收藏0
  • 阿里云前端周刊 - 第 18 期

    摘要:然鵝在過去的兩個月里,對的理解發(fā)生了一波三折的變化。發(fā)布自版本發(fā)布之后,一直致力于提升版本迭代速度,盡可能地通過小的更新來修復(fù)存在的問題。 推薦 1. 深入淺出 React 高階組件 https://zhuanlan.zhihu.com/p/... 由高階函數(shù)引申高階組件,高階組件是接受 React 組件作為輸入,輸出一個新的 React 組件的組件,本文介紹了在 React 工程中如...

    luck 評論0 收藏0
  • 前端每周清單半年盤點之 React 與 ReactNative 篇

    摘要:前端每周清單半年盤點之與篇前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點分為新聞熱點開發(fā)教程工程實踐深度閱讀開源項目巔峰人生等欄目。與求同存異近日,宣布將的構(gòu)建工具由遷移到,引發(fā)了很多開發(fā)者的討論。 前端每周清單半年盤點之 React 與 ReactNative 篇 前端每周清單專注前端領(lǐng)域內(nèi)容,以對外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點;分為...

    Barry_Ng 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<