今天我们继续来根据Redux的文档来学习其源码,前面我们讲了Redux的createStoreAPI,今天我们来看看另一个我们日常比较常用的APIcombineReducers
首先我们都知道combineReducers的作用就是将拆分的小的reducer合并为一个大的reducer,官网的示例是这样子的
import { combineReducers } from 'redux';
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp;
👌下面我们深入源码看看combineReducers究竟做了啥
/**
* Turns an object whose values are different reducer functions, into a single
* reducer function. It will call every child reducer, and gather their results
* into a single state object, whose keys correspond to the keys of the passed
* reducer functions.
*
* @param {Object} reducers An object whose values correspond to different
* reducer functions that need to be combined into one. One handy way to obtain
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
* undefined for any action. Instead, they should return their initial state
* if the state passed to them was undefined, and the current state for any
* unrecognized action.
*
* @returns {Function} A reducer function that invokes every reducer inside the
* passed object, and builds a state object with the same shape.
*/
export default function combineReducers(reducers) {
var finalReducers = pick(reducers, (val) => typeof val === 'function');
Object.keys(finalReducers).forEach(key => {
var reducer = finalReducers[key];
if (typeof reducer(undefined, { type: ActionTypes.INIT }) === '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.`
);
}
var type = Math.random().toString(36).substring(7).split('').join('.');
if (typeof reducer(undefined, { type }) === '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.`
);
}
});
var defaultState = mapValues(finalReducers, () => undefined);
var stateShapeVerified;
return function combination(state = defaultState, action) {
var finalState = mapValues(finalReducers, (reducer, key) => {
var newState = reducer(state[key], action);
if (typeof newState === 'undefined') {
throw new Error(getErrorMessage(key, action));
}
return newState;
});
if (process.env.NODE_ENV !== 'production') {
if (!stateShapeVerified) {
verifyStateShape(state, finalState);
stateShapeVerified = true;
}
}
return finalState;
};
}
粗看以下代码量还是比较多的但是去除里面的一些Error提示之后,其实也没有几行,我们一行一行来分析下。
首先从注释代码上看其传入值是一个Object而且Object对象的每个值都是一个reducer函数;返回值是一个调用了传入子reducer且生成一个state对象的函数。
step1
var finalReducers = pick(reducers, (val) => typeof val === 'function');
这里的pick函数在源码中已经引入过,总的来说作用就是,挑选出对象中满足第二个传入函数条件的值,并返回由满足条件的值生成的一个新对象,在这儿的作用就是,选出reducer中value类型为函数的值并赋值给finalState。
step2
对finalReducers进行遍历,首先遇到的两个if判断是判断当我们传入的默认state为undefined的时候,如果actionType是init或者是一个随机的type那么,返回的值不应该是undefined。否则报错
setp3
var defaultState = mapValues(finalReducers, () => undefined);
mapValues为源码中import的函数,作用是对finalReducers中的每个value值应用,传入的函数并且,返回最终的Object。比如说Redux文档中的示例经过这一步返回的就是
{
visibilityFilter:undefined,
todos:undefined
}
step4
var stateShapeVerified;
定义一个stateShapeVerifiedflag
####step5
下面就是最关键的组合函数了,也就是combineReducers最终会返回给我们的函数,我们看看返回的这个函数究竟有什么作用,首先他将,defaultState作为了state的默认值。接下看看这个函数
var finalState = mapValues(finalReducers, (reducer, key) => {
var newState = reducer(state[key], action);
if (typeof newState === 'undefined') {
throw new Error(getErrorMessage(key, action));
}
return newState;
});
这里再一次用到了mapValues这个工具函数,在工具函数里面主要的逻辑就是,对传入的finalReducers,的每个值执行,传入的函数,然后返回这个一个新的对象,那么在这个代码里面我们可以看到,传入的函数的作用就是对传入的action执行每个reducer并得到更新后的state对象,那么这整个函数的作用也就是得到了一个新的state。同时这也解释了为什么我们说,发出的action是全局的,因为一个action是要在全部的子reducer中都要执行一遍。
finaly
if (process.env.NODE_ENV !== 'production') {
if (!stateShapeVerified) {
verifyStateShape(state, finalState);
stateShapeVerified = true;
}
}
最后这个函数主要是对返回的state和初始state的key进行比较看看又没有违规的key出现,如果有则报错。
最后:由于语言功底差可能解释的不到位,如果有看不懂的欢迎留言询问。