Skip to content

Commit 8f2b747

Browse files
author
Yan.Huang
committed
update actions.md's translation
1 parent 9071ec3 commit 8f2b747

File tree

1 file changed

+90
-92
lines changed

1 file changed

+90
-92
lines changed

docs/zh-cn/actions.md

Lines changed: 90 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,133 @@
11
# Actions
22

3-
Actions 是用于 dispatch mutations 的函数。Actions 可以是异步的,一个 action 可以 dispatch 多个 mutations.
4-
5-
一个 action 描述了有什么事情应该发生,把本应该在组件中调用的逻辑细节抽象出来。当一个组件需要做某件事时,只需要调用一个 action —— 组件本身并不需要关心具体的后果:不需要提供回调函数也不需要期待返回值,因为 actions 的结果一定是 state 产生了变化,而 state 一旦变化,便会触发组件的 DOM 更新。 这样,组件便完全和 action 的具体逻辑解耦了。
6-
7-
因此,我们通常在 actions 中做 API 相关的请求。通过 actions 的封装,我们使得组件和 mutations 都不需要关心这些异步逻辑。
8-
93
> Vuex actions 和 Flux 中的 "action creators" 是等同的概念,但是我觉得这个定义常让人感到困惑(比如分不清 actions 和 action creators)。
104
11-
### 简单的 Actions
12-
13-
最简单的情况下,一个 action 即触发一个 mutation。Vuex 提供一个快捷的方式去定义这样的 actions:
5+
Actions 是用于分发 mutations 的函数。按照惯例,Vuex 的第一个参数是 store 实例,附加上可选的自定义参数。
146

157
``` js
16-
const store = new Vuex.Store({
17-
state: {
18-
count: 1
19-
},
20-
mutations: {
21-
INCREMENT (state, x) {
22-
state.count += x
23-
}
24-
},
25-
actions: {
26-
// 快捷定义
27-
// 只要提供 mutation 名
28-
increment: 'INCREMENT'
29-
}
30-
})
8+
// 最简单的 action
9+
function increment (store) {
10+
store.dispatch('INCREMENT')
11+
}
12+
13+
// 带附加参数的 action
14+
// 使用 ES2015 参数解构
15+
function incrementBy ({ dispatch }, amount) {
16+
dispatch('INCREMENT', amount)
17+
}
3118
```
3219

33-
调用 action:
20+
乍一眼看上去感觉多此一举,我们直接分发 mutations 岂不更方便?实际上并非如此,还记得 **mutations 必须同步执行**这个限制么?Actions 就不受约束!我们可以在 action 内部执行**异步**操作:
3421

3522
``` js
36-
store.actions.increment(1)
23+
function incrementAsync ({ dispatch }) {
24+
setTimeout(() => {
25+
dispatch('INCREMENT')
26+
}, 1000)
27+
}
3728
```
3829

39-
这相当于调用:
30+
来看一个更加实际的购物车示例,涉及到**调用异步 API****分发多重 mutations**
31+
4032

4133
``` js
42-
store.dispatch('INCREMENT', 1)
34+
function checkout ({ dispatch, state }, products) {
35+
// 把当前购物车的物品备份起来
36+
const savedCartItems = [...state.cart.added]
37+
// 发出检出请求,然后乐观地清空购物车
38+
dispatch(types.CHECKOUT_REQUEST)
39+
// 购物 API 接受一个成功回调和一个失败回调
40+
shop.buyProducts(
41+
products,
42+
// 成功操作
43+
() => dispatch(types.CHECKOUT_SUCCESS),
44+
// 失败操作
45+
() => dispatch(types.CHECKOUT_FAILURE, savedCartItems)
46+
)
47+
}
4348
```
4449

45-
注意所有传递给 action 的参数同样会传递给 mutation handler.
50+
请谨记一点,必须通过分发 mutations 来处理调用异步 API 的结果,而不是依赖返回值或者是传递回调来处理结果。基本原则就是:**Actions 除了分发 mutations 不能造成别的副作用**
4651

47-
### 正常 Actions
52+
### 在组件中调用 Actions
4853

49-
对于包含逻辑或是异步操作的 actions,则用函数来定义。Actions 函数获得的第一个参数永远是其所属的 store 实例
54+
你可能发现了 action 函数必须依赖 store 实例才能执行。从技术上讲,我们可以在组件的方法内部调用 `action(this.$store)` 来触发一个 action,但这样写起来有失优雅。更好的做法是把 action 暴露到组件的方法中,便可以直接在模板中引用它。我们可以使用 `vuex.actions` 选项来这么做
5055

5156
``` js
52-
const store = new Vuex.Store({
53-
state: {
54-
count: 1
55-
},
56-
mutations: {
57-
INCREMENT (state, x) {
58-
state += x
59-
}
60-
},
61-
actions: {
62-
incrementIfOdd: (store, x) => {
63-
if ((store.state.count + 1) % 2 === 0) {
64-
store.dispatch('INCREMENT', x)
65-
}
57+
// 组件内部
58+
import { incrementBy } from './actions'
59+
60+
const vm = new Vue({
61+
vuex: {
62+
getters: { ... }, // state getters
63+
actions: {
64+
incrementBy // ES6 同名对象字面量缩写
6665
}
6766
}
6867
})
6968
```
7069

71-
通常我们会用 ES6 的参数解构 (arguments destructuring) 语法来使得函数体更简洁
70+
上述代码所做的就是把原生的 `incrementBy` action 绑定到组件的 store 实例中,暴露给组件一个 `vm.increamentBy` 实例方法。所有传递给 `vm.increamentBy` 的参数变量都会排列在 store 变量后面然后一起传递给原生的 action 函数,所以调用
7271

7372
``` js
74-
// ...
75-
actions: {
76-
incrementIfOdd: ({ dispatch, state }, x) => {
77-
if ((state.count + 1) % 2 === 0) {
78-
dispatch('INCREMENT', x)
79-
}
80-
}
81-
}
73+
vm.incrementBy(1)
8274
```
8375

84-
同时,简单 actions 的快捷定义其实只是如下函数的语法糖
76+
等价于
8577

8678
``` js
87-
actions: {
88-
increment: 'INCREMENT'
89-
}
90-
// ... 上面的定义等同于:
91-
actions: {
92-
increment: ({ dispatch }, ...payload) => {
93-
dispatch('INCREMENT', ...payload)
94-
}
95-
}
79+
incrementBy(vm.$store, 1)
9680
```
9781

98-
### 异步 Actions
82+
虽然多写了一些代码,但是组件的模板中调用 action 更加省力了:
83+
84+
``` html
85+
<button v-on:click="incrementBy(1)">increment by one</button>
86+
```
9987

100-
异步 actions 同样使用函数定义
88+
还可以给 action 取别名
10189

10290
``` js
103-
// ...
104-
actions: {
105-
incrementAsync: ({ dispatch }, x) => {
106-
setTimeout(() => {
107-
dispatch('INCREMENT', x)
108-
}, 1000)
91+
// 组件内部
92+
import { incrementBy } from './actions'
93+
94+
const vm = new Vue({
95+
vuex: {
96+
getters: { ... },
97+
actions: {
98+
plus: incrementBy // 取别名
99+
}
109100
}
110-
}
111-
```
101+
})
102+
103+
这样 action 就会被绑定为 `vm.plus` 而不是 `vm.increamentBy` 了。
112104

113-
举个更实在的例子,比如一个购物车。当用户结账时,我们可能需要在 checkout 这一个 action 中触发多个不同的 mutations:一个在开始检查购物车时触发,一个在成功后触发,还有一个在失败时触发。
105+
### 内联 Actions
106+
107+
如果一个 action 只跟一个组件相关,可以采用简写语法把它定义成一行:
114108

115109
``` js
116-
// ...
117-
actions: {
118-
checkout: ({ dispatch, state }, products) => {
119-
// 保存结账前的购物车内容
120-
const savedCartItems = [...state.cart.added]
121-
// 发出结账的请求,并且清空购物车
122-
dispatch(types.CHECKOUT_REQUEST)
123-
// 假设我们的后台 API 接受一个成功回调和一个错误回调
124-
shop.buyProducts(
125-
products,
126-
// 结账成功
127-
() => dispatch(types.CHECKOUT_SUCCESS),
128-
// 结账失败,将购物车恢复到结账之前的状态
129-
() => dispatch(types.CHECKOUT_FAILURE, savedCartItems)
130-
)
110+
const vm = new Vue({
111+
vuex: {
112+
getters: { ... },
113+
actions: {
114+
plus: ({ dispatch }) => dispatch('INCREMENT')
115+
}
131116
}
132-
}
117+
})
133118
```
134119

135-
这里有相对复杂的异步逻辑,但是购物车的组件依然只需要简单地调用 `store.actions.checkout(products)` 即可.
120+
### 绑定所有 Actions
121+
122+
如果你想简单地把所有引入的 actions 都绑定到组件中:
123+
124+
``` js
125+
import * as actions from './actions'
126+
127+
const vm = new Vue({
128+
vuex: {
129+
getters: { ... },
130+
actions // 绑定所有 actions
131+
}
132+
})
133+
```

0 commit comments

Comments
 (0)