亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

eccozhou / 2996人閱讀

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

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

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

改變思維方式

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

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

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

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

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

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

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

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

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

2、接下來,我們必須對這些行動(dòng)狀態(tài)發(fā)生的變化作出反應(yīng)。 因?yàn)樗鼈冎辉谏芷谥邪l(fā)生過一次,所以我們不會(huì)使用長期運(yùn)行的效果,如autorun()reaction()。 我們也不希望這些效果在執(zhí)行后存在。 好吧,這給我們留下了一個(gè)選擇:....
....
....

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

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

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

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

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

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

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

markActionComplete("login");

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

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

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

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

Example 2: 作為工作流程的一部分啟動(dòng)操作

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

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

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");
    }
});

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

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

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

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

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

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

workflow.transitionTo("start");

workflow.transitionTo("finalize");

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

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

通過react-router進(jìn)行路由

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

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

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

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

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

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是我們以前從未見過的。 通過在我們的類實(shí)例(this)上應(yīng)用它,我們得到一個(gè)ES5相當(dāng)于創(chuàng)建一個(gè)@observable類屬性。

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

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

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

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ā)生更改時(shí)自動(dòng)觸發(fā)。 請注意,要使MobX正確跟蹤您的observable,您必須使用解除引用。

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

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

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

const instance = new FormData();

// Simple console logger
autorun(() => {
    // input的每一次輸入,結(jié)果都會(huì)觸發(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 = "pavan@pixelingene.com";
instance.acceptTerms = true;

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

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

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

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

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

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

1、我們先來看看我們正在處理的組件。 我們正在創(chuàng)建一組隨機(jī)報(bào)告其負(fù)載狀態(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è)計(jì)可觀察狀態(tài)。 組件的load()不會(huì)按特定順序完成。 所以我們需要一個(gè)可觀察的數(shù)組來存儲(chǔ)每個(gè)組件的加載狀態(tài)。 我們還將跟蹤每個(gè)組件的報(bào)告狀態(tài)。

當(dāng)所有組件都已報(bào)告時(shí),我們可以通知組件集的最終加載狀態(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的計(jì)算屬性跟蹤組件完成其加載的時(shí)間。 mark()是我們改變可觀察狀態(tài)的動(dòng)作方法。

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

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

when()所有組件都已reported時(shí),跟蹤器可以報(bào)告最終加載的狀態(tài)。 我們在這里使用,因?yàn)槲覀冋诘却龡l件變?yōu)檎妫╰his.reported)。 報(bào)告的副作用只需要發(fā)生一次,非常適合when()

以下代碼負(fù)責(zé)以上事項(xiàng):

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()實(shí)際上不是解決方案的一部分,但用于記錄報(bào)告。 這是了解我們的解決方案是否有效的好方法。

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ù)期工作。 在組件報(bào)告時(shí),我們記錄每個(gè)組件的當(dāng)前加載狀態(tài)。 當(dāng)所有人報(bào)告時(shí),this.reported變?yōu)閠rue,我們看到“All Components Loaded”消息。

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

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

設(shè)置變異動(dòng)作方法以更改可觀察狀態(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)用實(shí)例

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

    Barry_Ng 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<