Redux 源码解读之 combineReducers
combineReducers 源码地址:node_modules/redux/src/combineReducers.js。
combineReducers 的核心功能是为了使业务逻辑能够更加颗粒化,用户可以设计多个 reducer,而 combineReducers 就可以对这些 reducer 进行合并。
一、深复制一份 reducers
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
if (process.env.NODE_ENV !== 'production') {
if (typeof reducers[key] === 'undefined') {
warning(`No reducer provided for key "${key}"`)
}
}
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
reducers 是 combineReducers 方法的参数,该参数是一个键值对对象。以上源码中,首先获取对象的键值数组,然后循坏其数组,并将每一个键值对赋值给 finalReducers。以此实现将所有的 reducers 深度复制给 finalReducers。同时获取新的 finalReducers 键值对数组 finalReducerKeys 。
二、断言每一个 reducer
let unexpectedKeyCache
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
let shapeAssertionError
try {
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e
}
通过 assertReducerShape 方法对新的 finalReducers 断言。
function assertReducerShape(reducers) {
Object.keys(reducers).forEach(key => {
const reducer = reducers[key]
const 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.`
)
}
})
}
对每一个 reducer 传一个初始的 type, 判断其返回值是否是 undefined ,如果是 undefined ,则 创建 Error 对象。也就是报错提示。
三、对比新旧 state
return function combination(state, action) {
if (state === void 0) {
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;
var nextState = {};
for (var _i = 0; _i < finalReducerKeys.length; _i++) {
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key];
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(_key, action);
throw new Error(errorMessage);
}
nextState[_key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
return hasChanged ? nextState : state;
};
combineReducers 方法返回了一个闭包函数,这个闭包函数接收传入的 state 和action。
- 如果 state 为 undefined,即 void 0,state 重置为 空对象 {}。
- 如果有断言错误,捕捉错误。
- 将变量 hasChanged 初始为 false,下一个 state ,即 nextState 初始化为 空对象 {}。
- 取出finalReducers 中所有的 key 和 value(也就是每一个 reducer),获取当前 reducer 作用后的 state,将当前 state 和 action 作为参数获取下一个 state 。
- 对 hasChanged 重新赋值,如果 下一个 state 和当前 state 不相等,hasChanged 为 true,否则为 false。
- hasChanged 为 true 时,返回下一个 state,否则返回当前传入的 state。