1.combineReducers旨在整合切分后reducer,并将state树切分至各个reduce进行管理,这样做的好处是每个reduce只用管理它自己的state内容,此时state树中的结构变成{reducerName: reducerStateBySelf},即key为redcuer函数的名字,value为reducer各自所管理的state。
2.combineReducer的原理:
首先combineReducers需要传入切分的reducer对象,然后combineReducers内部会对传入对象进行遍历,然后会执行各个reducer函数,由于此时actionType为undefined,所以各reducer会返回默认的state,传入对象遍历完毕后,会在combineReducers组合成一个新的state树对象返回,这个state树的结构如1中所说。然后当触发某个action操作时,也是会执行组合后的reducer函数,然后在函数内部再进行遍历,每个reducer都会再执行一次,然后根据相应的action做相应的操作,更新对应reducer所管理的state。(注:此时actionType应该是唯一的值,否则的话可能引起拥有相同action的reducer同时进行更新)。
以下是combineReducers函数源码,可帮助理解:
//注意首次在调用该方法的时候传入的state对象是空对象,由于根据reducer的key取值的时候都是undefined,所以会返回相应reducer的默认state。
function combineReducers(reducers) {
var reducerKeys = Object.keys(reducers);
var finalReducers = {};
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
//如果是生产环境,如果传入的reducer是undefined则报警告
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning("No reducer provided for key \"" + key + "\"");
}
}
//如果传入的object的value是函数,即为reduce函数,则将函数复制一下
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key];
}
}
var finalReducerKeys = Object.keys(finalReducers);
var unexpectedKeyCache;
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {};
}
var shapeAssertionError;
try {
assertReducerShape(finalReducers);
} catch (e) {
shapeAssertionError = e;
}
return function combination(state, action) {
if (state === void 0) { //void 0 即为undefined
state = {};
}
if (shapeAssertionError) {
throw shapeAssertionError;
}
if (process.env.NODE_ENV !== 'production') {
var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
if (warningMessage) {
warning(warningMessage);
}
}
var hasChanged = false; //用来标记各reducer执行过后state是否改变
var nextState = {}; //用于返回新的state树
//遍历过滤后的存放reducer的对象
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key]; //获取到各reduce
var nextStateForKey = reducer(previousStateForKey, action); //执行完相应的reduce后返回新的state
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(_key, action);
throw new Error(errorMessage);
}
nextState[_key] = nextStateForKey; //将state更新到总的state树
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
return hasChanged ? nextState : state; //根据state树是否发生变化返回前state或修改后的state
};
}
//此函数为了校验reduce是否符合标准,是否有初始化的state值。
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(function (key) {
var reducer = reducers[key];
var initialState = reducer(undefined, {
type: ActionTypes.INIT
});
if (typeof initialState === 'undefined') {
throw new Error("Reducer \"" + key + "\" returned undefined during initialization. " + "If the state passed to the reducer is undefined, you must " + "explicitly return the initial state. The initial state may " + "not be undefined. If you don't want to set a value for this reducer, " + "you can use null instead of undefined.");
}
if (typeof reducer(undefined, {
type: ActionTypes.PROBE_UNKNOWN_ACTION()
}) === 'undefined') {
throw new Error("Reducer \"" + key + "\" returned undefined when probed with a random type. " + ("Don't try to handle " + ActionTypes.INIT + " or other actions in \"redux/*\" ") + "namespace. They are considered private. Instead, you must return the " + "current state for any unknown actions, unless it is undefined, " + "in which case you must return the initial state, regardless of the " + "action type. The initial state may not be undefined, but can be null.");
}
});
}









网友评论