在使用 redux 作为状态管理时, 应用中一般都是各个模块单独对应一个 reducer, 最终组合成一个大的 reducer 传入 store, 所以 redux 提供了一个 combineReducers 函数, 它的作用就是接收一个子 reducer 组成的对象, 返回一个新的 reducer 函数.
首先, 介绍一下只有一个根 reducer 的情况
- // reducer
- function counter(state = { apple: 0}, action) {
- switch (action.type) {
- case INCREMENT:
- return {
- apple: state.apple + 1
- };
- case DECREMENT:
- return {
- apple: state.apple - 1
- };
- default:
- return state;
- }
- }
- export default createStore(counter, applyMiddleware(thunk));
如上, 当只有一个 reducer 时, 直接传入 createStore 即可. 注意: 这里有一个细节, 对于初始化 state tree, 至少需要在 reducer 中指定默认值或者在 createStore 中传入 initialState, 否则报错. 即:
- // 指定默认值
- function counter(state = { apple: 0 }, action) {...}
- // 或者传入 initialState
- const initialState = { apple:0 }
- export default createStore(counter,initialState, applyMiddleware(thunk));
当两者都传值时, createStore 的 initialState 优先级更高.
当应用中有多个子 reducer 时, 那么就需要使用 combineReducers 函数将它们组合起来, 如下, 请看 combineReducers 函数
- /* combineReducers.js */
- function assertReducerShape(reducers) {
- Object.keys(reducers).forEach(key => {
- const reducer = reducers[key];
- // 初始化检查, 每个子 reducer 必须指定默认值, 否则检查不通过
- const initialState = reducer(undefined, { type: '@@redux/INIT' })
- if (typeof initialState === 'undefined') {
- throw new Error(
- `Reducer "${key}" return undefined during initiallization.`
- )
- }
- })
- }
- // 接收子 reducer 组成的对象
- export default function combineReducers(reducers) {
- // 第一步, 对 reducers 进行过滤, 非 function 的 reducer 都将被过滤掉
- const finalReducers = Object.keys(reducers).reduce(
- (finalReducers, key) => {
- if (typeof reducers[key] === 'function') {
- finalReducers[key] = reducers[key]
- }
- return finalReducers;
- }, {}
- )
- // 第二步, 初始化检查每个子 reducer 是否传入默认的 initialState.
- let shapeAssertionError;
- try {
- assertReducerShape(finalReducers)
- } catch (e) {
- shapeAssertionError = e;
- }
- // 第三步, 返回总 reducer
- return (state = {}, action) => {
- if (shapeAssertionError) {
- throw shapeAssertionError;
- }
- return Object.keys(finalReducers).reduce((nextState, key) => {
- const nextStateForKey = finalReducers[key](state[key], action)
- if (typeof nextStateForKey === 'undefined') {
- throw new Error(`Reducer "${key}" return undefined.`)
- }
- nextState[key] = nextStateForKey;
- return nextState
- }, {})
- }
- }
由源码得知, 当使用复合型 reducers 时, 每个子 reducer 都必须传递默认值, 以此来通过初始化检查, 否则报错. 若同时在 createStore 中传递 initialState 参数, 则初始化时使用 initialState, 注意, initialState 的 键名需要和 reducers 对象的键名保持一致, 否则报错.
- // 下面是一个测试 demo
- // const aReducer = (state = { a: 0 }, action) => {
- // switch (action.type) {
- // case 'add':
- // return state.a + 1;
- // default:
- // return state;
- // }
- // }
- // const bReducer = (state = { b: 0 }, action) => {
- // switch (action.type) {
- // case 'add':
- // return state.b + 1;
- // default:
- // return state;
- // }
- // }
- // const reducer = combineReducers({ aState: aReducer, bState: bReducer })
- // const initialState = {
- // aState: {
- // a: 4
- // },
- // bState: {
- // b: 5
- // }
- // }
- // console.log(reducer(initialState, { type: 'add' }))
来源: http://www.jianshu.com/p/6e76b783abf2