# Reducer
reducer 就是一個純函數,接收舊的 state 和 action,返回新的 state。
```js
(previousState, action) => newState
```
可以理解為舊狀態向新狀態的一個映射,其中action就是改變這個狀態的方法。
`previousState --(action)--> newState`
## 處理 Reducer 關系時的注意事項
開發復雜的應用時,不可避免會有一些數據相互引用。建議你盡可能地把 state 范式化,不存在嵌套。把所有數據放到一個對象里,每個數據以 ID 為主鍵,不同實體或列表間通過 ID 相互引用數據。把應用的 state 想像成數據庫。這種方法在 normalizr 文檔里有詳細闡述。例如,實際開發中,在 state 里同時存放 `todosById: { id -> todo }` 和 `todos: array<id>` 是比較好的方式。
## Reducer 的純凈性
之所以稱作 reducer 是因為它將被傳遞給 `Array.prototype.reduce(reducer, ?initialValue)` 方法。保持 reducer 純凈非常重要。永遠不要在 reducer 里做這些操作:
- 修改傳入參數;
- 執行有副作用的操作,如 API 請求和路由跳轉;
- 調用非純函數,如 Date.now() 或 Math.random()。
所謂純凈性,就是只要傳入參數相同,返回計算得到的下一個 state 就一定相同。沒有特殊情況、沒有副作用,沒有 API 請求、沒有變量修改,單純執行計算。
## Action 的處理
一個約定俗成的做法是,actions 擁有一個常量 type 幫助 reducer (或 Flux 中的 Stores ) 識別它們。我們建議你使用 string 而不是 Symbols 作為 action type ,因為 string 是可序列化的,而使用 Symbols 會毫無必要地使記錄和重演變得困難。
有以下一個 Reducer :
```js
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
default:
return state
}
}
```
在使用action的時候需要注意:
1. 不要修改 state。 使用 Object.assign() 新建了一個副本。不能這樣使用 Object.assign(state, { visibilityFilter: action.filter }),因為它會改變第一個參數的值。你必須把第一個參數設置為空對象。你也可以開啟對ES7提案對象展開運算符的支持, 從而使用 { ...state, ...newState } 達到相同的目的。
2. 在 default 情況下返回舊的 state。遇到未知的 action 時,一定要返回舊的 state。
### Object.assign 須知
Object.assign() 是 ES6 特性,但多數瀏覽器并不支持。你要么使用 polyfill,Babel 插件,或者使用其它庫如 _.assign() 提供的幫助方法。
### switch 和樣板代碼須知
switch 語句并不是嚴格意義上的樣板代碼。Flux 中真實的樣板代碼是概念性的:更新必須要發送、Store 必須要注冊到 Dispatcher、Store 必須是對象(開發同構應用時變得非常復雜)。為了解決這些問題,Redux 放棄了 event emitters(事件發送器),轉而使用純 reducer。
很不幸到現在為止,還有很多人存在一個誤區:根據文檔中是否使用 switch 來決定是否使用它。如果你不喜歡 switch,完全可以自定義一個 createReducer 函數來接收一個事件處理函數列表。
### action type 的命名規范
在 Flux 中,傳統的想法是將每個 action type 定義為 string 常量:
```js
const ADD_TODO = 'ADD_TODO';
const REMOVE_TODO = 'REMOVE_TODO';
const LOAD_ARTICLE = 'LOAD_ARTICLE';
```
這么做的優勢?人們通常聲稱常量不是必要的。對于小項目也許正確。 對于大的項目,將 action types 定義為常量有如下好處:
幫助維護命名一致性,因為所有的 action type 匯總在同一位置。
有時,在開發一個新功能之前你想看到所有現存的 actions 。而你的團隊里可能已經有人添加了你所需要的action,而你并不知道。
Action types 列表在 Pull Request 中能查到所有添加,刪除,修改的記錄。這能幫助團隊中的所有人及時追蹤新功能的范圍與實現。
如果你在導入一個 Action 常量的時候拼寫錯誤,你會得到 undefined 。當你納悶 action 被分發出去而什么也沒發生的時候,一個拼寫錯誤更容易被發現。
你的項目的約定取決與你自己。開始時,可能用的是 inline string,之后轉為常量,也許之后將他們歸為一個獨立文件。Redux 不會給予任何建議,選擇你自己最喜歡的。
#### 常量表示的 Reducers
使用以上命名規則的 action,可以使用常量表示法直接生成 Reducers
```js
export const todos = createReducer([], {
[ADD_TODO](state, action) {
let text = action.text.trim();
return [...state, text];
}
})
```
- 簡介
- 第一章 React入門
- 1.1 創建一個React項目
- 1.2 組件
- 1.3 JSX
- 1.4 eject
- 1.5 渲染
- 第二章 React組件
- 2.1 組件定義
- 2.2 數據處理
- 2.2.1 props
- 2.2.2 state
- 2.3 生命周期
- 2.3.1 裝載過程
- 2.3.2 更新過程
- 2.3.3 卸載過程
- 2.4 事件處理
- 2.5 條件渲染
- 2.6 列表渲染
- 第三章 React高級
- 3.1 靜態類型檢查
- 3.1.1 flow
- 3.1.2 typescript
- 3.2 React Developer Tools
- 第四章 Redux狀態管理
- 4.1 安裝與配置
- 4.2 一個簡單的計數器開始
- 4.3 Store
- 4.3.1 獲取state
- 4.3.2 subscribe
- 4.4 Action
- 4.4.1 Action Creators
- 4.5 Reducer
- 4.5.1 Reducer 的拆分
- 4.6 與其他狀態管理工具的對比
- 第五章 React-Router路由
- 參考資料