# 状态更改
使用 action 注解来修改 state 状态。
import { makeObservable, observable, action } from "mobx"
class Doubler {
value = 0
constructor(value) {
makeObservable(this, {
value: observable,
increment: action.bound
})
}
set increment() {
this.value++
this.value++
}
}
const doubler = new Doubler()
// 这样调用 increment 是安全的, 因为它已经被绑定了。
setInterval(doubler.increment, 1000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 使用 action 包装函数
action
不仅仅是一个注解,更是一个高阶函数,因此一切涉及修改 state 的操作,都应该将其标记为 action。action
不会触发 state 的追踪。
示例:
const ResetButton = ({ formState }) => (
<button
onClick={action(e => {
formState.resetPendingUploads()
formState.resetValues()
e.stopPropagation()
})}
>
Reset form
</button>
)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# action 绑定
为了解决 this 的指向问题,可以使用 action.bound
使 this 始终正确的绑定在函数内部。
(使用 makeAutoObservable(o, {}, { autoBind: true })
会自动绑定所有的 actions 和 flows)
import { makeAutoObservable } from "mobx"
class Doubler {
value = 0
constructor(value) {
makeAutoObservable(this, {}, { autoBind: true })
}
increment() {
this.value++
this.value++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 临时执行的 action
可以使用 runInAction(fn)
来立即执行一个临时定义的 action。这在异步进程中非常有用。
import { observable, runInAction } from "mobx"
const state = observable({ value: 0 })
const getValue=()=>{
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(10)
},1000)
})
}
runInAction(async() => {
const data=await getValue()
state=data
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 异步执行 action
任何的 state 的更改操作都应该处于 action 作用域中,因此,当处理 Promise 时,涉及 state 修改的操作都应当标识为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"
})
)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# async / await 的替代方案
async / await 作为现代 js 中常用的异步方案,在 mobx 中不推荐使用,而是推荐 flow 作为替代。
Why? 因为
async / await
的本质是promise
的包装,如上面的fetchProjects
,就是把await
后的代码放到Promise.then()
函数里,把catch
部分的代码放到.catch
的回调函数里,还是同样需要将异步的执行部分用action
来包装起来,说白了,其本质还是一个Promise
任务
# 使用 flow 进行替代
实现:generator 迭代器
import { flow, makeAutoObservable, flowResult } from "mobx"
class Store {
githubProjects = []
state = "pending"
constructor() {
makeAutoObservable(this, {
fetchProjects: flow
})
}
// 注意星号, 这是一个 generator 函数!
*fetchProjects() {
this.githubProjects = []
this.state = "pending"
try {
// Yield 代替 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())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# flow.bound
用法与 action.bound
类似,使this
始终被正确绑定在函数内部。