如何在Mobx里实现一个异步的action?
2021-09-11大约5分钟
使用Mobx的时候,store里的状态的改变,默认情况下,必须经过action来操作,这可以让状态修改的操作在代码里面更加明确,也可以更好地组织代码。
对于普通同步的action,这个参考最简单的Mobx例子就可以了。但是对于异步的action,这点需要留意一下。
如果是用Promise
,那么then()
函数里传入的应该是一个action;如果是用async
/await
, await
之后的代码在运行时实际上仍旧是一个类似callback的一个函数里,因此也需要是一个action。这种情况下,可以有两个选择:
- 将callback定义成一个action。
- 使用
runInAction
这个工具函数。
比如:
mobx.configure({ enforceActions: true })
class Store {
@observable githubProjects = []
@observable state = "pending" // "pending" / "done" / "error"
@action
async fetchProjects() {
this.githubProjects = []
this.state = "pending"
try {
const projects = await fetchGithubProjectsSomehow()
const filteredProjects = somePreprocessing(projects)
// await 之后,再次修改状态需要动作:
runInAction(() => {
this.state = "done"
this.githubProjects = filteredProjects
})
} catch (error) {
runInAction(() => {
this.state = "error"
})
}
}
}
另外一种更简单的用法呢,则是用flow。flow实际上借助的是generator
的语法。虽然generator
是个不太常见的词,但是没关系,如果熟悉async
/await
,那么在实际写代码的时候,把async
换成*
,把await
换成yield
就可以了。这样可以让代码更简洁:
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()
调用flow的action的时候,还是可以照样用await来调用的。