首先,讓我們來(lái)給 action 下個(gè)定義。
Actions 是把數(shù)據(jù)從應(yīng)用(譯者注:這里之所以不叫 view 是因?yàn)檫@些數(shù)據(jù)有可能是服務(wù)器響應(yīng),用戶輸入或其它非 view 的數(shù)據(jù) )傳到 store 的有效載荷。它是 store 數(shù)據(jù)的惟一來(lái)源。用法是通過(guò) store.dispatch()
把 action 傳到 store。
添加新 todo 任務(wù)的 action 是這樣的:
const ADD_TODO = 'ADD_TODO';
{
type: 'ADD_TODO',
text: 'Build my first Redux app'
}
Action 本質(zhì)是 JavaScript 普通對(duì)象。我們約定,action 內(nèi)使用一個(gè)字符串類型的 type
字段來(lái)表示將要執(zhí)行的動(dòng)作。多數(shù)情況下,type
會(huì)被定義成字符串常量。當(dāng)應(yīng)用規(guī)模越來(lái)越大時(shí),建議使用單獨(dú)的模塊或文件來(lái)存放 action。
import { ADD_TODO, REMOVE_TODO } from '../actionTypes';
樣板文件使用提醒
使用單獨(dú)的模塊或文件來(lái)定義 action type 常量并不是必須的,甚至根本不需要定義。對(duì)于小應(yīng)用來(lái)說(shuō),使用字符串做 action type 更方便些。不過(guò),在大型應(yīng)用中最多把它們顯式地定義成常量。參照 減少樣板代碼 獲取保持代碼干凈的實(shí)踐經(jīng)驗(yàn)。
除了 type
字段外,action 對(duì)象的結(jié)構(gòu)完全取決于你。參照 Flux 標(biāo)準(zhǔn) Action 獲取如何組織 action 的建議。
這時(shí),我們還需要再添加一個(gè) action type 來(lái)標(biāo)記任務(wù)完成。因?yàn)閿?shù)據(jù)是存放在數(shù)組中的,我們通過(guò) index
來(lái)標(biāo)識(shí)任務(wù)。實(shí)際項(xiàng)目中一般會(huì)在新建內(nèi)容的時(shí)候生成惟一的 ID 做標(biāo)識(shí)。
{
type: COMPLETE_TODO,
index: 5
}
action 中傳遞的數(shù)據(jù)越少越好。比如,這里傳遞 index
就比把整個(gè)任務(wù)對(duì)象傳過(guò)去要好。
最后,再添加一個(gè) action 類型來(lái)表示當(dāng)前展示的任務(wù)狀態(tài)。
{
type: SET_VISIBILITY_FILTER,
filter: SHOW_COMPLETED
}
Action 創(chuàng)建函數(shù) 就是生成 action 的方法?!癮ction” 和 “action 創(chuàng)建函數(shù)” 這兩個(gè)概念很容易混在一起,使用時(shí)最好注意區(qū)分。
在 傳統(tǒng)的 Flux 實(shí)現(xiàn)中,當(dāng)調(diào)用 action 創(chuàng)建函數(shù)時(shí),一般會(huì)觸發(fā)一個(gè) dispatch,像這樣:
function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
};
dispatch(action);
}
不同的是,Redux 中的 action 創(chuàng)建函數(shù)是 純函數(shù),它沒有任何副作用,只是返回 action 對(duì)象而已。
function addTodo(text) {
return {
type: ADD_TODO,
text
};
}
這讓代碼更易于測(cè)試和移植。只需把 action 創(chuàng)建函數(shù)的結(jié)果傳給 dispatch()
方法即可實(shí)例化 dispatch。
dispatch(addTodo(text));
dispatch(completeTodo(index));
或者創(chuàng)建一個(gè) 被綁定的 action 創(chuàng)建函數(shù) 來(lái)自動(dòng) dispatch:
const boundAddTodo = (text) => dispatch(addTodo(text));
const boundCompleteTodo = (index) => dispatch(CompleteTodo(index));
可以這樣調(diào)用:
boundAddTodo(text);
boundCompleteTodo(index);
store 里能直接通過(guò) store.dispatch()
調(diào)用 dispatch()
方法,但是多數(shù)情況下你會(huì)使用 react-redux 提供的 connect()
幫助器來(lái)調(diào)用。bindActionCreators()
可以自動(dòng)把多個(gè) action 創(chuàng)建函數(shù) 綁定到 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 創(chuàng)建函數(shù)
*/
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 };
}
現(xiàn)在讓我們 開發(fā)一些 reducers 來(lái)指定發(fā)起 action 后 state 應(yīng)該如何更新。
高級(jí)用戶建議
如果你已經(jīng)熟悉這些基本概念且已經(jīng)完成了這個(gè)示例,不要忘了看一下在 高級(jí)教程 中的 異步 actions,你將學(xué)習(xí)如何處理 AJAX 響應(yīng)和如何把 action 創(chuàng)建函數(shù)組合成異步控制流。
更多建議: