Mobx6-action(中文文檔)

使用actions更新狀態(tài)

用法:

  • action 注解(es規(guī)范中稱之為裝飾器,感覺Mobx的文檔描述不是很準確忿墅,但是后面翻譯已原文為準)
  • action(fn)
  • action(name, fn)

所有的應(yīng)用程序都有action融求。一個action是用于修改state的任意一段代碼片段咬像。原則上,action總是響應(yīng)event而觸發(fā)生宛。例如:點擊了按鈕县昂、輸入一些內(nèi)容、接收到新的websocket推送消息等等陷舅。

MobX要求你聲明動作七芭,盡管makeAutoObservable可以自動完成很多工作。
Actions能夠幫助你更好的組織代碼并且提供以下的性能優(yōu)勢:

  1. actiontransactions中執(zhí)行蔑赘。在最外層的action完成之前,不會更新任何觀察者(比如 computed的值预明,或者使用了observerreact組件)缩赛,以確保在動作完成之前,動作的過程中產(chǎn)生的中間值或不完整值對應(yīng)用程序的其余部分不可見撰糠。
  2. 默認情況下酥馍,不允許在action之外的地方更新state(這一點和之前的版本有區(qū)別,之前的版本需要手動開啟嚴格模式, 具體可參考changelog)阅酪。這有助于清楚的定位觸發(fā)state更新在代碼庫中的位置旨袒。
  3. action注解應(yīng)該只在修改state的函數(shù)上使用。那些用來派生出其他的信息函數(shù)(比如 查詢特定的值术辐,過濾等等)不應(yīng)該使用action注解砚尽,這樣Mobx能夠跟蹤這些函數(shù)的調(diào)用(其實這里的情況應(yīng)該使用computed

makeObserable & makeAutoObservable & action.bound & arrow function

使用action包裹函數(shù)

為了盡可能利用Mobx的事務(wù)特性,action應(yīng)該盡可能的向外傳遞(最開始意圖觸發(fā)修改state的函數(shù))辉词。如果一個類的方法修改的state,最好將其標記為action必孤。最好將事件處理函數(shù)標記為action,因為它是最外層的事務(wù)瑞躺。
隨后調(diào)用兩個動作的一個未被標記action的事件處理函數(shù)將會生成兩個事務(wù)敷搪。
為了方便創(chuàng)建基于事件回調(diào)的動作兴想,action不僅僅是一個注解,也是一個高階函數(shù)赡勘。它可以傳入一個函數(shù)作為參數(shù)來調(diào)用嫂便。在那種場景下,它將返回一個具有同樣簽名的包裝action闸与。

例如在React里毙替,一個onClick處理器可以如下包裝:

const ResetButton = ({ formState }) => (
    <button
        onClick={action(e => {
            formState.resetPendingUploads()
            formState.resetValues()
            e.stopPropagation()
        })}
    >
        Reset form
    </button>
)

為了調(diào)試的目的,我們建議或者命名被包裹的函數(shù),或者傳入一個name作為action的第一個參數(shù)几迄。

NOTE: actions不會被追蹤蔚龙。
actions另一個特性是他們不會被追蹤。
當從副作用或計算值內(nèi)部調(diào)用action時(非常罕見S承病)木羹,action讀取的observable值不會被計入派生的依賴項。
makeAutoObservable解孙,extendObservableobservable使用一種稱為autoAction的特殊動作坑填,它將在運行時確定函數(shù)是derivation還是action

action.bound

使用:

  • action.bound (annotation)
    action.bound注解可以用于自動綁定一個方法到正確的實例上(保證this上下文的引用正確性),以便始終正確的將this綁定到函數(shù)內(nèi)部弛姜。

TIP
相比action.bound脐瑰,更喜歡箭頭函數(shù)(推薦使用箭頭函數(shù)的方式來綁定上下文)
如果你想要使用makeAutoObservable結(jié)合綁定 actions, 通常使用箭頭函數(shù)會更簡單廷臼。

import { makeAutoObservable } from "mobx"

class Doubler {
    value = 0

    constructor(value) {
        makeAutoObservable(this)
    }

    increment = () => {
        this.value++ 苍在;勞動法非法。
KH
        this.value++
    }
}

runInAction

用法:

  • runInAction(fn)
    使用這個輔助方法來創(chuàng)建一個立即執(zhí)行的臨時aciton,在異步流程中會非常有用荠商。

Asynchronous actions

本質(zhì)上寂恬,在Mobx中異步流程不需要任何特殊的對待,因為所有的reactions將會自動發(fā)生更新莱没,而不管它們在何時被引起的初肉。而且,由于可觀察對象是可變的饰躲,因此在整個操作過程中保持對它們的引用通常是安全的牙咏。然后,在一個異步流程中嘹裂,更新observable的每一步都應(yīng)該被標記為action妄壶。可以通過利用上述API以多種方式實現(xiàn)這一點焦蘑,如下所示盯拱。

例如,當處理promises的時候,更新state的程序應(yīng)該被action包裹(還記的action可以作為一個函數(shù)直接調(diào)用嗎狡逢?)或者應(yīng)該是一個action,如下所示:

Wrap handlers in action

Promise resolution handlers are handled in-line, but run after the original action finished, so they need to be wrapped by action:

import { action, makeAutoObservable } from "mobx"

class Store {
    githubProjects = []
    state = "pending" // "pending", "done" or "error"

    constructor() {
        makeAutoObservable(this)
    }

    fetchProjects() {
        this.githubProjects = []
        this.state = "pending"
        fetchGithubProjectsSomehow().then(
            action("fetchSuccess", projects => {
                const filteredProjects = somePreprocessing(projects)
                this.githubProjects = filteredProjects
                this.state = "done"
            }),
            action("fetchError", error => {
                this.state = "error"
            })
        )
    }
}

使用 flow替代 of async / await {??}

用法:

  • flow (注解)
  • flow(function* (args) { }

flow 是async / await的可選替代方案宁舰,它使使用MobX操作更加容易。generator function
功能作為其唯一輸入奢浑。在生成器內(nèi)部蛮艰,您可以通過yield somePromse實現(xiàn)同步鏈寫法(使用yield somePromise替換wait somePromise)。然后雀彼,flow將確保生成器在產(chǎn)生的承諾解決時繼續(xù)運行或拋出壤蚜。

所有,flowasync / await的替代方案徊哑,這種方式不需要進一步使用action包裹袜刷。可以按照如下步驟應(yīng)用:

  1. 使用flow包裹你的異步函數(shù)
  2. 使用function *替換async
  3. 使用yield替換await

代碼如下:

import { flow, makeAutoObservable, flowResult } from "mobx"

class Store {
    githubProjects = []
    state = "pending"

    constructor() {
        makeAutoObservable(this, {
            fetchProjects: flow
        })
    }

    // Note the star, this a generator function!
    *fetchProjects() {
        this.githubProjects = []
        this.state = "pending"
        try {
            // Yield instead of await.
            const projects = yield fetchGithubProjectsSomehow()
            const filteredProjects = somePreprocessing(projects)
            this.state = "done"
            this.githubProjects = filteredProjects
        } catch (error) {
            this.state = "error"
        }
    }
}

const store = new Store()
const projects = await flowResult(store.fetchProjects())

需要注意的是莺丑,上面例子中的flowResult函數(shù)只有當使用typescript的時候才需要著蟹。
因為使用flow裝飾一個方法,它將會使用一個promise包裹返回的generator,但是typescript并不知道這種轉(zhuǎn)換梢莽,所以flowResult將確保typescript知道這種類型改變萧豆。

makeAutoObservable將會自動推動generator函數(shù)為flow

NOTE 也可以在對象的屬性上使用flow
類似于action, flow也可以也可以直接包裹一個函數(shù)使用昏名,上面的例子也可以是使用如下代碼書寫涮雷。

import { flow } from "mobx"

class Store {
    githubProjects = []
    state = "pending"

    fetchProjects = flow(function* (this: Store) {
        this.githubProjects = []
        this.state = "pending"
        try {
            // yield instead of await.
            const projects = yield fetchGithubProjectsSomehow()
            const filteredProjects = somePreprocessing(projects)
            this.state = "done"
            this.githubProjects = filteredProjects
        } catch (error) {
            this.state = "error"
        }
    })
}

const store = new Store()
const projects = await store.fetchProjects()

這樣寫法的好處是,如果你使用typescript轻局,不再需要flowResult洪鸭,缺點是傳入this,確保上下文引用正確仑扑。

補充:你可以選擇使用bind來綁定你的上下文卿嘲。

import { flow } from "mobx"

class Store {
    githubProjects = []
    state = "pending"

    fetchProjects = flow(function* () {
        this.githubProjects = []
        this.state = "pending"
        try {
            // yield instead of await.
            const projects = yield fetchGithubProjectsSomehow()
            const filteredProjects = somePreprocessing(projects)
            this.state = "done"
            this.githubProjects = filteredProjects
        } catch (error) {
            this.state = "error"
        }
    })
}.bind(this); // here we use bind.

const store = new Store()
const projects = await store.fetchProjects()

Cancelling flows{??}

flow的另外一個好處是可以取消。flow的返回值是一個promise,這個返回值是通過generator函數(shù)的返回值夫壁。這個返回的promise有個額外的cancel()方法,可以用來打斷正在執(zhí)行的generator并且取消它沃疮。try / finally的代碼將任然會被執(zhí)行盒让。

Disabling mandatory actions {??}

默認,Mobx6以及之后的版本將會要求你使用actions來改變state司蔬。但是你也可以使用Mobx 配置邑茄,禁用這一行為。查看enforceActions
章節(jié)俊啼。比如,這在單元測試配置中非常有用,單元測試中這些警告沒有什么價值同木。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秕硝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洲尊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躯护,死亡現(xiàn)場離奇詭異,居然都是意外死亡丽涩,警方通過查閱死者的電腦和手機棺滞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來内狸,“玉大人检眯,你說我怎么就攤上這事±サ” “怎么了锰瘸?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昂灵。 經(jīng)常有香客問我避凝,道長,這世上最難降的妖魔是什么眨补? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任管削,我火速辦了婚禮,結(jié)果婚禮上撑螺,老公的妹妹穿的比我還像新娘含思。我一直安慰自己,他們只是感情好甘晤,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布含潘。 她就那樣靜靜地躺著,像睡著了一般线婚。 火紅的嫁衣襯著肌膚如雪遏弱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天塞弊,我揣著相機與錄音漱逸,去河邊找鬼泪姨。 笑死,一個胖子當著我的面吹牛饰抒,可吹牛的內(nèi)容都是我干的肮砾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼循集,長吁一口氣:“原來是場噩夢啊……” “哼唇敞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咒彤,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤疆柔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后镶柱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旷档,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年歇拆,在試婚紗的時候發(fā)現(xiàn)自己被綠了鞋屈。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡厂庇,死狀恐怖输吏,靈堂內(nèi)的尸體忽然破棺而出贯溅,到底是詐尸還是另有隱情,我是刑警寧澤译柏,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布鄙麦,位于F島的核電站镊折,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜与纽,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望影所。 院中可真熱鬧僚碎,春花似錦、人聲如沸卷中。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愤估。三九已至,卻和暖如春由驹,著一層夾襖步出監(jiān)牢的瞬間震捣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工润樱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留壹若,地道東北人皂冰。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像赂蕴,于是被迫代替她去往敵國和親舶胀。 傳聞我的和親對象是個殘疾皇子碧注,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本文不詳細介紹 MobX 相關(guān)的所有內(nèi)容萍丐,但已經(jīng)可以覆蓋開發(fā)中 99% 的場景逝变。不講其他內(nèi)容是為了避免干擾我們的思...
    jetzhliu閱讀 3,860評論 0 5
  • http://blog.poetries.top/2018/08/31/acq-mobx/ 關(guān)注公眾號獲取更多資訊...
    程序員poetry閱讀 1,756評論 0 5
  • 在 Skillshare 我們擁抱改變壳影;不僅因為把它寫在公司的前景宣言中很酷声怔,也因為改變確實有必要醋火。這是我們近期將...
    pansly閱讀 1,493評論 0 3
  • 因為之前一直用的 Vue 全家桶芥驳,所以轉(zhuǎn) React 的時候我就采用類比的方式來理解 Mobx 了。建議熟悉 Vu...
    VioletJack閱讀 3,497評論 0 4
  • Mobx解決的問題 傳統(tǒng)React使用的數(shù)據(jù)管理庫為Redux假抄。Redux要解決的問題是統(tǒng)一數(shù)據(jù)流丽猬,數(shù)據(jù)流完全可控...
    前端大神888閱讀 441評論 1 0