轉載自:https://www.jianshu.com/p/66dd328726d7
異步action
action只能影響正在運行的函數,而無法影響當前函數調用的異步操作 。
action 包裝/裝飾器只會對當前運行的函數作出反應,而不會對當前運行函數所調用的函數(不包含在當前函數之內)作出反應 ,
也就是說promise的then或async語句,並且在回調函數中某些狀態改變了,這些回調函數也應該包裝在action中。
(1)第一種方案,使用action關鍵字來包裝promises的回調函數。
// 第一種寫法
(1)第一種方案,使用action關鍵字來包裝promises的回調函數。
// 第一種寫法
class Store { @observable githubProjects = [] @observable state = "pending" // "pending" / "done" / "error" @action 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" }) ) } }
// 第二種寫法
class Store { @observable githubProjects = [] @observable state = "pending" // "pending" / "done" / "error" @action fetchProjects() { this.githubProjects = [] this.state = "pending" fetchGithubProjectsSomehow().then( projects => { const filteredProjects = somePreprocessing(projects) // 將修改放入一個異步動作中 runInAction(() => { this.githubProjects = filteredProjects this.state = "done" }) }, error => { runInAction(() => { this.state = "error" }) } ) } }
第二種方案,用async function來處理業務,那么我們可以使用runInAction這個API來解決之前的問題 。
import {observable, action, useStrict, runInAction} from 'mobx'; useStrict(true); class Store { @observable name = ''; @action load = async () => { const data = await getData(); // await之后,修改狀態需要動作 runInAction(() => { this.name = data.name; }); } }
- flows
然而,更好的方式是使用 flow 的內置概念。它們使用生成器。一開始可能看起來很不適應,但它的工作原理與 async / await 是一樣的。只是使用 function * 來代替 async,使用 yield 代替 await 。 使用 flow 的優點是它在語法上基本與 async / await 是相同的 (只是關鍵字不同),並且不需要手動用 @action 來包裝異步代碼,這樣代碼更簡潔。
flow 只能作為函數使用,不能作為裝飾器使用。 flow 可以很好的與 MobX 開發者工具集成,所以很容易追蹤 async 函數的過程。
mobx.configure({ enforceActions: true }) class Store { @observable githubProjects = [] @observable state = "pending" fetchProjects = flow(function * () { // <- 注意*號,這是生成器函數! this.githubProjects = [] this.state = "pending" try { const projects = yield fetchGithubProjectsSomehow() // 用 yield 代替 await const filteredProjects = somePreprocessing(projects) // 異步代碼塊會被自動包裝成動作並修改狀態 this.state = "done" this.githubProjects = filteredProjects } catch (error) { this.state = "error" } }) }