上面的 reducer 仅仅是实现了 “新增待办事项” 的 state 的处理
    我们还有计数器的功能,下面我们继续增加计数器 “增加 1” 的功能:

    1. /** 本代码块记为 code-8 **/
    2. var initState = { counter: 0, todos: [] }
    3. function reducer(state, action) {
    4. if (!state) return initState // 若是初始化可立即返回应用初始状态
    5. var nextState = _.cloneDeep(state) // 否则二话不说先克隆
    6. switch (action.type) {
    7. case 'ADD_TODO': // 新增待办事项
    8. nextState.todos.push(action.payload)
    9. break
    10. case 'INCREMENT': // 计数器加 1
    11. nextState.counter = nextState.counter + 1
    12. break
    13. }
    14. return nextState
    15. }

    如果说还有其他的动作,都需要在 code-8 这个 reducer 中继续堆砌处理逻辑
    但我们知道,计数器 与 待办事项 属于两个不同的模块,不应该都堆在一起写
    如果之后又要引入新的模块(例如留言板),该 reducer 会越来越臃肿
    此时就是 combineReducers 大显身手的时刻:

    1. 目录结构如下
    2. reducers/
    3. ├── index.js
    4. ├── counterReducer.js
    5. ├── todosReducer.js

    code-8 reducercode-9 rootReducer 的功能是一样的,但后者的各个子 reducer 仅维护对应的那部分 state
    其可操作性、可维护性、可扩展性大大增强


    下面继续来深入使用 。一直以来我们的应用状态都是只有两层,如下所示:

    1. state
    2. ├── counter: 0
    3. ├── todos: []

    如果说现在又有一个需求:在待办事项模块中,存储用户每次操作(增删改)的时间,那么此时应用初始状态树应为:

    1. ├── counter: 0
    2. ├── todo
    3. ├── optTime: []
    4. ├── todoList: [] # 这其实就是原来的 todos!

    那么对应的 reducer 就是:

    1. /* reducers/index.js */
    2. import { combineReducers } from 'redux'
    3. import counterReducer from './counterReducer'
    4. import todoReducers from './todoReducers/'
    5. const rootReducer = combineReducers({
    6. counter: counterReducer,
    7. todo: todoReducers
    8. })
    9. export default rootReducer
    10. =================================================
    11. /* reducers/todoReducers/index.js */
    12. import { combineReducers } from 'redux'
    13. import optTimeReducer from './optTimeReducer'
    14. import todoListReducer from './todoListReducer'
    15. const todoReducers = combineReducers({
    16. optTime: optTimeReducer,
    17. todoList: todoListReducer
    18. })
    19. export default todoReducers
    20. -------------------------------------------------
    21. /* reducers/todosReducers/optTimeReducer.js */
    22. export default function optTimeReducer(optTime = [], action) {
    23. // 咦?这里怎么没有 switch-case 分支?谁说 reducer 就一定包含 switch-case 分支的?
    24. return action.type.includes('TODO') ? [ ...optTime, new Date() ] : optTime
    25. }
    26. -------------------------------------------------
    27. /* reducers/todosReducers/todoListReducer.js */
    28. export default function todoListReducer(todoList = [], action) {
    29. switch (action.type) {
    30. case 'ADD_TODO':
    31. return [ ...todoList, action.payload ]
    32. default:
    33. return todoList
    34. }
    35. }
    1. counterReducer(counter, action) -------------------- counter
    2. rootReducer(state, action) —→∑ optTimeReducer(optTime, action) ------ optTime nextState
    3. ↘—→∑ todo
    4. todoListReducer(todoList,action) ----- todoList
    5. 注:左侧表示 dispatch 分发流,∑ 表示 combineReducers;右侧表示各实体 reducer 的返回值,最后汇总整合成 nextState

    看了上图,您应该能直观感受到为何取名为 reducer 了吧?把 state 分而治之,极大减轻开发与维护的难度

    ⊙ 源码分析