在调用Redux中的combineReducers方法时,我们的参数是一个Object,其中key是state中的数据标识,value是reducer,那么该方法内部又是如何处理的呢?
首先看下该方法的关键源码实现:
export default function combineReducers(reducers) {
var reducerKeys = Object.keys(reducers);
var finalReducers = {};
for (let reducerKey in reducerKeys) {
//如果reducer不是方法,则filter掉
if (typeof reducers[reducerKey] === 'function') {
finalReducers[key] = reducers[reducerKeys]
}
}
var finalReducerKeys = Object.keys(finalReducers);
return (state = {}, action) => {
let hasChanged = false;
let nextState = {};
// 当dispatch被调用时,会循环调用每个reducer
for (let key in finalReducerKeys) {
let reducer = finalReducers[key];
let previousStateForKey = state[key];
let nextStateForKey = reducer(previousStateForKey, action);
// 如果reducer处理返回的数据为undefined的话,则会抛异常,所以如果需要返回undefined时,可以考虑返回null进行处理。
if (typeof nextStateForKey === 'undefined') {
throw new Error("state is undefined")
}
nextState[key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
//如果有数据发生变化时,则将nextState返回,否则返回原来的state,这也是为什么在reducer中对于object数据不能直接修改属性值的原因,这有可能导致返回原来的state。
return hasChanged ? nextState : state;
}
}
综上所述,在定义reducer时,我们需要注意以下几点:
- reducer不管是初始值,还是对于某个action处理之后的返回值,都不能是undefined。
- reducer中对于Object或者Array类型的数据不能直接修改属性值,这会导致state数据不发生变化。可以考虑使用Object.assign或者ES6的…来实现。