Просмотр исходного кода

update actions.md's translation

Yan.Huang 9 лет назад
Родитель
Сommit
8f2b747180
1 измененных файлов с 90 добавлено и 92 удалено
  1. 90 92
      docs/zh-cn/actions.md

+ 90 - 92
docs/zh-cn/actions.md

@@ -1,135 +1,133 @@
 # Actions
 # Actions
 
 
-Actions 是用于 dispatch mutations 的函数。Actions 可以是异步的,一个 action 可以 dispatch 多个 mutations.
-
-一个 action 描述了有什么事情应该发生,把本应该在组件中调用的逻辑细节抽象出来。当一个组件需要做某件事时,只需要调用一个 action —— 组件本身并不需要关心具体的后果:不需要提供回调函数也不需要期待返回值,因为 actions 的结果一定是 state 产生了变化,而 state 一旦变化,便会触发组件的 DOM 更新。 这样,组件便完全和 action 的具体逻辑解耦了。
-
-因此,我们通常在 actions 中做 API 相关的请求。通过 actions 的封装,我们使得组件和 mutations 都不需要关心这些异步逻辑。
-
 > Vuex actions 和 Flux 中的 "action creators" 是等同的概念,但是我觉得这个定义常让人感到困惑(比如分不清 actions 和 action creators)。
 > Vuex actions 和 Flux 中的 "action creators" 是等同的概念,但是我觉得这个定义常让人感到困惑(比如分不清 actions 和 action creators)。
 
 
-### 简单的 Actions
-
-最简单的情况下,一个 action 即触发一个 mutation。Vuex 提供一个快捷的方式去定义这样的 actions:
+Actions 是用于分发 mutations 的函数。按照惯例,Vuex 的第一个参数是 store 实例,附加上可选的自定义参数。
 
 
 ``` js
 ``` js
-const store = new Vuex.Store({
-  state: {
-    count: 1
-  },
-  mutations: {
-    INCREMENT (state, x) {
-      state.count += x
-    }
-  },
-  actions: {
-    // 快捷定义
-    // 只要提供 mutation 名
-    increment: 'INCREMENT'
-  }
-})
+// 最简单的 action
+function increment (store) {
+  store.dispatch('INCREMENT')
+}
+
+// 带附加参数的 action
+// 使用 ES2015 参数解构
+function incrementBy ({ dispatch }, amount) {
+  dispatch('INCREMENT', amount)
+}
 ```
 ```
 
 
-调用 action:
+乍一眼看上去感觉多此一举,我们直接分发 mutations 岂不更方便?实际上并非如此,还记得 **mutations 必须同步执行**这个限制么?Actions 就不受约束!我们可以在 action 内部执行**异步**操作:
 
 
 ``` js
 ``` js
-store.actions.increment(1)
+function incrementAsync ({ dispatch }) {
+  setTimeout(() => {
+    dispatch('INCREMENT')
+  }, 1000)
+}
 ```
 ```
 
 
-这相当于调用:
+来看一个更加实际的购物车示例,涉及到**调用异步 API** 和 **分发多重 mutations**:
+
 
 
 ``` js
 ``` js
-store.dispatch('INCREMENT', 1)
+function checkout ({ dispatch, state }, products) {
+  // 把当前购物车的物品备份起来
+  const savedCartItems = [...state.cart.added]
+  // 发出检出请求,然后乐观地清空购物车
+  dispatch(types.CHECKOUT_REQUEST)
+  // 购物 API 接受一个成功回调和一个失败回调
+  shop.buyProducts(
+    products,
+    // 成功操作
+    () => dispatch(types.CHECKOUT_SUCCESS),
+    // 失败操作
+    () => dispatch(types.CHECKOUT_FAILURE, savedCartItems)
+  )
+}
 ```
 ```
 
 
-注意所有传递给 action 的参数同样会传递给 mutation handler.
+请谨记一点,必须通过分发 mutations 来处理调用异步 API 的结果,而不是依赖返回值或者是传递回调来处理结果。基本原则就是:**Actions 除了分发 mutations 不能造成别的副作用**。
 
 
-### 正常 Actions
+### 在组件中调用 Actions
 
 
-对于包含逻辑或是异步操作的 actions,则用函数来定义。Actions 函数获得的第一个参数永远是其所属的 store 实例:
+你可能发现了 action 函数必须依赖 store 实例才能执行。从技术上讲,我们可以在组件的方法内部调用 `action(this.$store)` 来触发一个 action,但这样写起来有失优雅。更好的做法是把 action 暴露到组件的方法中,便可以直接在模板中引用它。我们可以使用 `vuex.actions` 选项来这么做
 
 
 ``` js
 ``` js
-const store = new Vuex.Store({
-  state: {
-    count: 1
-  },
-  mutations: {
-    INCREMENT (state, x) {
-      state += x
-    }
-  },
-  actions: {
-    incrementIfOdd: (store, x) => {
-      if ((store.state.count + 1) % 2 === 0) {
-        store.dispatch('INCREMENT', x)
-      }
+// 组件内部
+import { incrementBy } from './actions'
+
+const vm = new Vue({
+  vuex: {
+    getters: { ... }, // state getters
+    actions: {
+      incrementBy // ES6 同名对象字面量缩写
     }
     }
   }
   }
 })
 })
 ```
 ```
 
 
-通常我们会用 ES6 的参数解构 (arguments destructuring) 语法来使得函数体更简洁
+上述代码所做的就是把原生的 `incrementBy` action 绑定到组件的 store 实例中,暴露给组件一个 `vm.increamentBy` 实例方法。所有传递给 `vm.increamentBy` 的参数变量都会排列在 store 变量后面然后一起传递给原生的 action 函数,所以调用:
 
 
 ``` js
 ``` js
-// ...
-actions: {
-  incrementIfOdd: ({ dispatch, state }, x) => {
-    if ((state.count + 1) % 2 === 0) {
-      dispatch('INCREMENT', x)
-    }
-  }
-}
+vm.incrementBy(1)
 ```
 ```
 
 
-同时,简单 actions 的快捷定义其实只是如下函数的语法糖
+等价于:
 
 
 ``` js
 ``` js
-actions: {
-  increment: 'INCREMENT'
-}
-// ... 上面的定义等同于:
-actions: {
-  increment: ({ dispatch }, ...payload) => {
-    dispatch('INCREMENT', ...payload)
-  }
-}
+incrementBy(vm.$store, 1)
 ```
 ```
 
 
-### 异步 Actions
+虽然多写了一些代码,但是组件的模板中调用 action 更加省力了:
+
+``` html
+<button v-on:click="incrementBy(1)">increment by one</button>
+```
 
 
-异步 actions 同样使用函数定义:
+还可以给 action 取别名
 
 
 ``` js
 ``` js
-// ...
-actions: {
-  incrementAsync: ({ dispatch }, x) => {
-    setTimeout(() => {
-      dispatch('INCREMENT', x)
-    }, 1000)
+// 组件内部
+import { incrementBy } from './actions'
+
+const vm = new Vue({
+  vuex: {
+    getters: { ... },
+    actions: {
+      plus: incrementBy // 取别名
+    }
   }
   }
-}
-```
+})
+
+这样 action 就会被绑定为 `vm.plus` 而不是 `vm.increamentBy` 了。
 
 
-举个更实在的例子,比如一个购物车。当用户结账时,我们可能需要在 checkout 这一个 action 中触发多个不同的 mutations:一个在开始检查购物车时触发,一个在成功后触发,还有一个在失败时触发。
+### 内联 Actions
+
+如果一个 action 只跟一个组件相关,可以采用简写语法把它定义成一行:
 
 
 ``` js
 ``` js
-// ...
-actions: {
-  checkout: ({ dispatch, state }, products) => {
-    // 保存结账前的购物车内容
-    const savedCartItems = [...state.cart.added]
-    // 发出结账的请求,并且清空购物车
-    dispatch(types.CHECKOUT_REQUEST)
-    // 假设我们的后台 API 接受一个成功回调和一个错误回调
-    shop.buyProducts(
-      products,
-      // 结账成功
-      () => dispatch(types.CHECKOUT_SUCCESS),
-      // 结账失败,将购物车恢复到结账之前的状态
-      () => dispatch(types.CHECKOUT_FAILURE, savedCartItems)
-    )
+const vm = new Vue({
+  vuex: {
+    getters: { ... },
+    actions: {
+      plus: ({ dispatch }) => dispatch('INCREMENT')
+    }
   }
   }
-}
+})
 ```
 ```
 
 
-这里有相对复杂的异步逻辑,但是购物车的组件依然只需要简单地调用 `store.actions.checkout(products)` 即可.
+### 绑定所有 Actions
+
+如果你想简单地把所有引入的 actions 都绑定到组件中:
+
+``` js
+import * as actions from './actions'
+
+const vm = new Vue({
+  vuex: {
+    getters: { ... },
+    actions // 绑定所有 actions
+  }
+})
+```