# Action
首先,讓我們來給 action 下個定義。
**Actions** 是把數據從應用(譯者注:這里之所以不叫 view 是因為這些數據有可能是服務器響應,用戶輸入或其它非 view 的數據 )傳到 store 的有效載荷。它是 store 數據的**惟一**來源。用法是通過 [`store.dispatch()`](#) 把 action 傳到 store。
添加新 todo 任務的 action 是這樣的:
~~~
const ADD_TODO = 'ADD_TODO';
~~~
~~~
{
type: 'ADD_TODO',
text: 'Build my first Redux app'
}
~~~
Action 本質是 JavaScript 普通對象。我們約定,action 內使用一個字符串類型的 `type` 字段來表示將要執行的動作。多數情況下,`type` 會被定義成字符串常量。當應用規模越來越大時,建議使用單獨的模塊或文件來存放 action。
~~~
import { ADD_TODO, REMOVE_TODO } from '../actionTypes';
~~~
> ##### 樣板文件使用提醒
> 使用單獨的模塊或文件來定義 action type 常量并不是必須的,甚至根本不需要定義。對于小應用來說,使用字符串做 action type 更方便些。不過,在大型應用中最多把它們顯式地定義成常量。參照 [減少樣板代碼](#) 獲取保持代碼干凈的實踐經驗。
除了 `type` 字段外,action 對象的結構完全取決于你。參照 [Flux 標準 Action](https://github.com/acdlite/flux-standard-action) 獲取如何組織 action 的建議。
這時,我們還需要再添加一個 action type 來標記任務完成。因為數據是存放在數組中的,我們通過 `index` 來標識任務。實際項目中一般會在新建內容的時候生成惟一的 ID 做標識。
~~~
{
type: COMPLETE_TODO,
index: 5
}
~~~
**action 中傳遞的數據越少越好**。比如,這里傳遞 `index` 就比把整個任務對象傳過去要好。
最后,再添加一個 action 類型來表示當前展示的任務狀態。
~~~
{
type: SET_VISIBILITY_FILTER,
filter: SHOW_COMPLETED
}
~~~
### Action 創建函數
**Action 創建函數** 就是生成 action 的方法。“action” 和 “action 創建函數” 這兩個概念很容易混在一起,使用時最好注意區分。
在 [傳統的 Flux](http://facebook.github.io/flux) 實現中,當調用 action 創建函數時,一般會觸發一個 dispatch,像這樣:
~~~
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
};
dispatch(action);
}
~~~
不同的是,Redux 中的 action 創建函數是 **純函數**,它沒有任何副作用,只是返回 action 對象而已。
~~~
function addTodo(text) {
return {
type: ADD_TODO,
text
};
}
~~~
這讓代碼更易于測試和移植。只需把 action 創建函數的結果傳給 `dispatch()` 方法即可實例化 dispatch。
~~~
dispatch(addTodo(text));
dispatch(completeTodo(index));
~~~
或者創建一個 **被綁定的 action 創建函數** 來自動 dispatch:
~~~
const boundAddTodo = (text) => dispatch(addTodo(text));
const boundCompleteTodo = (index) => dispatch(CompleteTodo(index));
~~~
可以這樣調用:
~~~
boundAddTodo(text);
boundCompleteTodo(index);
~~~
store 里能直接通過 [`store.dispatch()`](#) 調用 `dispatch()` 方法,但是多數情況下你會使用 [react-redux](http://github.com/gaearon/react-redux) 提供的 `connect()` 幫助器來調用。[`bindActionCreators()`](#) 可以自動把多個 action 創建函數 綁定到 `dispatch()` 方法上。
### 源碼
### `actions.js`
~~~
/*
* action 類型
*/
export const ADD_TODO = 'ADD_TODO';
export const COMPLETE_TODO = 'COMPLETE_TODO';
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER';
/*
* 其它的常量
*/
export const VisibilityFilters = {
SHOW_ALL: 'SHOW_ALL',
SHOW_COMPLETED: 'SHOW_COMPLETED',
SHOW_ACTIVE: 'SHOW_ACTIVE'
};
/*
* action 創建函數
*/
export function addTodo(text) {
return { type: ADD_TODO, text };
}
export function completeTodo(index) {
return { type: COMPLETE_TODO, index };
}
export function setVisibilityFilter(filter) {
return { type: SET_VISIBILITY_FILTER, filter };
}
~~~
### 下一步
現在讓我們 [開發一些 reducers](#) 來指定發起 action 后 state 應該如何更新。
> ##### 高級用戶建議
> 如果你已經熟悉這些基本概念且已經完成了這個示例,不要忘了看一下在 [高級教程](#) 中的 [異步 actions](#),你將學習如何處理 AJAX 響應和如何把 action 創建函數組合成異步控制流。