调试项目
仓库:https://github.com/reduxjs/react-redux
项目:examples/todos
combineReducers
调试代码
import { combineReducers } from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'
export default combineReducers({
todos,
visibilityFilter
})
源码
export default function combineReducers(reducers: ReducersMapObject) {
const reducerKeys = Object.keys(reducers)
const finalReducers: ReducersMapObject = {}
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)
// This is used to make sure we don't warn about the same
// keys multiple times.
let unexpectedKeyCache: { [key: string]: true }
if (process.env.NODE_ENV !== 'production') {
unexpectedKeyCache = {}
}
let shapeAssertionError: Error
try {
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e
}
return function combination(
state: StateFromReducersMapObject<typeof reducers> = {},
action: AnyAction
) {
if (shapeAssertionError) {
throw shapeAssertionError
}
if (process.env.NODE_ENV !== 'production') {
const warningMessage = getUnexpectedStateShapeWarningMessage(
state,
finalReducers,
action,
unexpectedKeyCache
)
if (warningMessage) {
warning(warningMessage)
}
}
let hasChanged = false
const nextState: StateFromReducersMapObject<typeof reducers> = {}
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
hasChanged =
hasChanged || finalReducerKeys.length !== Object.keys(state).length
return hasChanged ? nextState : state
}
}
调用combineReducers
-
combineReducers
接收一个对象reducers,然后遍历reducers,筛出value为function的放入finalReducers
;
finalReducers
的结构在这个例子里是这样的
{
todos:function(){…},
visibilityFilter:function(){…}
}
- 使用
assertReducerShape
来校验,调用reducer时有没有传出默认的state; -
return combination
函数作为新的reducer
调用生成的新的reducer
就是调用上面提到的combination
函数
- 调用场景有主动调用和初始化调用。上篇说到,最开始的时候redux将会调用一次reducer去获取state的初始值;
- 使用传入的action,依次调用
finalReducers
对象里的方法。
也就是说,如果我们刚开始传入的todos、 visibilityFilter这两个reducers这里面有相同的action.type,那么逻辑将会依次被触发。
var _key = finalReducerKeys[_i];
var reducer = finalReducers[_key];
var previousStateForKey = state[_key];
var nextStateForKey = reducer(previousStateForKey, action);
值得注意的是,在调用的时候传入各个reducer的state仅限于state[key],而不是整个state
- 设定调用之后的state
nextState[_key] = nextStateForKey;
可以从这里得知,每个传入的reducer都对应同名的state的key,他们return的新state只会对state[key]的value做更新
- 执行结果
{
todos: []
visibilityFilter: "SHOW_ALL"
}
网友评论