# Reducer 邏輯復用
隨著應用程序的增長,在 reducer 邏輯中開始出現一些常見的模式。你可能會發現一部分 reducer 邏輯對于不同類型的數據做著相同的工作,你想通過對每種數據類型復用相同的公共邏輯來減少重復的代碼。或者,你可能想要在 store 中處理某個類型的數據的多個”實例“。然而,Redux store 采用全局結構的設計本身就是一種折衷:優點是易于追蹤應用程序的整體狀態,但是,也可能更難的”命中“那些需要更新特定一部分狀態的 action,特別是當你使用了 `combineReducers`。
例如,假設想在程序中追蹤多個計數器,分別命名為 A,B,和 C。定義初始的 `counter` reducer,然后使用 `combineReducers` 去設置狀態。
```javascript
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
const rootReducer = combineReducers({
counterA: counter,
counterB: counter,
counterC: counter
})
```
不幸的是,這樣設置有一個問題。因為 `combineReducers` 將會使用相同的 action 調用每一個 reducer,發送 `{type:'INCREMENT'}` 實際上將會導致所有三個計數器的值被增加,而不僅僅是其中一個。我們需要一些方法去封裝 `counter` 的邏輯,以此來保證只有我們關心的計數器被更新。
## 使用高階 Reducer 來定制行為
正如在 [Reducer 邏輯拆分](SplittingReducerLogic.html) 定義的那樣,高階 reducer 是一個接收 reducer 函數作為參數,并返回新的 reducer 函數的函數。它也可以被看作成一個“reducer 工廠”。`combineReducers` 就是一個高階 reduce 的例子。我們可以使用這種模式來創建特定版本的 reducer 函數,每個版本只響應特定的 action。
創建特定的 reducer 有兩種最常見的方式,一個是使用給定的前綴或者后綴生成新的 action 常量,另一個是在 action 對象上附加額外的信息。下面是它們大概的樣子:
```javascript
function createCounterWithNamedType(counterName = '') {
return function counter(state = 0, action) {
switch (action.type) {
case `INCREMENT_${counterName}`:
return state + 1
case `DECREMENT_${counterName}`:
return state - 1
default:
return state
}
}
}
function createCounterWithNameData(counterName = '') {
return function counter(state = 0, action) {
const { name } = action
if (name !== counterName) return state
switch (action.type) {
case `INCREMENT`:
return state + 1
case `DECREMENT`:
return state - 1
default:
return state
}
}
}
```
現在我們應該可以使用它們任何一個去生成我們特定的計數器 reducer,然后發送 action,并只會影響關心的那部分的 state:
```javascript
const rootReducer = combineReducers({
counterA: createCounterWithNamedType('A'),
counterB: createCounterWithNamedType('B'),
counterC: createCounterWithNamedType('C')
})
store.dispatch({ type: 'INCREMENT_B' })
console.log(store.getState())
// {counterA : 0, counterB : 1, counterC : 0}
```
我們在某種程度上也可以改變這個方法,創建一個更加通用的高階 reducer,它可以接收一個給定的 reducer,一個名字或者標識符:
```javascript
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
function createNamedWrapperReducer(reducerFunction, reducerName) {
return (state, action) => {
const { name } = action
const isInitializationCall = state === undefined
if (name !== reducerName && !isInitializationCall) return state
return reducerFunction(state, action)
}
}
const rootReducer = combineReducers({
counterA: createNamedWrapperReducer(counter, 'A'),
counterB: createNamedWrapperReducer(counter, 'B'),
counterC: createNamedWrapperReducer(counter, 'C')
})
```
甚至還可以寫一個通用的高階 reducer 過濾器:
```javascript
function createFilteredReducer(reducerFunction, reducerPredicate) {
return (state, action) => {
const isInitializationCall = state === undefined
const shouldRunWrappedReducer =
reducerPredicate(action) || isInitializationCall
return shouldRunWrappedReducer ? reducerFunction(state, action) : state
}
}
const rootReducer = combineReducers({
// 檢查后綴
counterA: createFilteredReducer(counter, action =>
action.type.endsWith('_A')
),
// 檢查 action 中的額外數據
counterB: createFilteredReducer(counter, action => action.name === 'B'),
// 響應所有的 'INCREMENT' action,但不響應 'DECREMENT'
counterC: createFilteredReducer(
counter,
action => action.type === 'INCREMENT'
)
})
```
這些基本的模式可以讓你在 UI 內處理一個智能連接的 component 的多個實例。對于像分頁或者排序這些通用的功能,可以復用相同的邏輯。
- 自述
- 介紹
- 動機
- 核心概念
- 三大原則
- 先前技術
- 學習資源
- 生態系統
- 示例
- 基礎
- Action
- Reducer
- Store
- 數據流
- 搭配 React
- 示例:Todo List
- 高級
- 異步 Action
- 異步數據流
- Middleware
- 搭配 React Router
- 示例:Reddit API
- 下一步
- 技巧
- 配置 Store
- 遷移到 Redux
- 使用對象展開運算符
- 減少樣板代碼
- 服務端渲染
- 編寫測試
- 計算衍生數據
- 實現撤銷重做
- 子應用隔離
- 組織 Reducer
- Reducer 基礎概念
- Reducer 基礎結構
- Reducer 邏輯拆分
- Reducer 重構示例
- combineReducers 用法
- combineReducers 進階
- State 范式化
- 管理范式化數據
- Reducer 邏輯復用
- 不可變更新模式
- 初始化 State
- 結合 Immutable.JS 使用 Redux
- 常見問題
- 綜合
- Reducer
- 組織 State
- 創建 Store
- Action
- 不可變數據
- 代碼結構
- 性能
- 設計哲學
- React Redux
- 其它
- 排錯
- 詞匯表
- API 文檔
- createStore
- Store
- combineReducers
- applyMiddleware
- bindActionCreators
- compose
- react-redux 文檔
- API
- 排錯