上面的 reducer
仅仅是实现了 “新增待办事项” 的 state
的处理
我们还有计数器的功能,下面我们继续增加计数器 “增加 1” 的功能:
/** 本代码块记为 code-8 **/
var initState = { counter: 0, todos: [] }
function reducer(state, action) {
if (!state) return initState // 若是初始化可立即返回应用初始状态
var nextState = _.cloneDeep(state) // 否则二话不说先克隆
switch (action.type) {
case 'ADD_TODO': // 新增待办事项
nextState.todos.push(action.payload)
break
case 'INCREMENT': // 计数器加 1
nextState.counter = nextState.counter + 1
break
}
return nextState
}
如果说还有其他的动作,都需要在 code-8
这个 reducer
中继续堆砌处理逻辑
但我们知道,计数器 与 待办事项 属于两个不同的模块,不应该都堆在一起写
如果之后又要引入新的模块(例如留言板),该 reducer
会越来越臃肿
此时就是 combineReducers
大显身手的时刻:
目录结构如下
reducers/
├── index.js
├── counterReducer.js
├── todosReducer.js
code-8 reducer
与 code-9 rootReducer
的功能是一样的,但后者的各个子 reducer
仅维护对应的那部分 state
其可操作性、可维护性、可扩展性大大增强
下面继续来深入使用 。一直以来我们的应用状态都是只有两层,如下所示:
state
├── counter: 0
├── todos: []
如果说现在又有一个需求:在待办事项模块中,存储用户每次操作(增删改)的时间,那么此时应用初始状态树应为:
├── counter: 0
├── todo
├── optTime: []
├── todoList: [] # 这其实就是原来的 todos!
那么对应的 reducer
就是:
/* reducers/index.js */
import { combineReducers } from 'redux'
import counterReducer from './counterReducer'
import todoReducers from './todoReducers/'
const rootReducer = combineReducers({
counter: counterReducer,
todo: todoReducers
})
export default rootReducer
=================================================
/* reducers/todoReducers/index.js */
import { combineReducers } from 'redux'
import optTimeReducer from './optTimeReducer'
import todoListReducer from './todoListReducer'
const todoReducers = combineReducers({
optTime: optTimeReducer,
todoList: todoListReducer
})
export default todoReducers
-------------------------------------------------
/* reducers/todosReducers/optTimeReducer.js */
export default function optTimeReducer(optTime = [], action) {
// 咦?这里怎么没有 switch-case 分支?谁说 reducer 就一定包含 switch-case 分支的?
return action.type.includes('TODO') ? [ ...optTime, new Date() ] : optTime
}
-------------------------------------------------
/* reducers/todosReducers/todoListReducer.js */
export default function todoListReducer(todoList = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [ ...todoList, action.payload ]
default:
return todoList
}
}
counterReducer(counter, action) -------------------- counter
↗ ↘
rootReducer(state, action) —→∑ ↗ optTimeReducer(optTime, action) ------ optTime ↘ nextState
↘—→∑ todo ↗
↘ todoListReducer(todoList,action) ----- todoList ↗
注:左侧表示 dispatch 分发流,∑ 表示 combineReducers;右侧表示各实体 reducer 的返回值,最后汇总整合成 nextState
看了上图,您应该能直观感受到为何取名为 reducer
了吧?把 state
分而治之,极大减轻开发与维护的难度