combineReducers.ts
函數(shù)重載聲明
首先是對combineReducers函數(shù)的重載无牵,重載了三個函數(shù),主要區(qū)別是傳參reducers類型的不同厂抖。
// 重載函數(shù)
export default function combineReducers<S>(
reducers: ReducersMapObject<S, any>
): Reducer<CombinedState<S>>
export default function combineReducers<S, A extends Action = AnyAction>(
reducers: ReducersMapObject<S, A>
): Reducer<CombinedState<S>, A>
export default function combineReducers<M extends ReducersMapObject>(
reducers: M
): Reducer<
CombinedState<StateFromReducersMapObject<M>>,
ActionFromReducersMapObject<M>
>
函數(shù)結(jié)構(gòu)
然后看看combineReducers函數(shù)的結(jié)構(gòu)茎毁。
可以看到combineReducers是個高階函數(shù),返回值也是一個函數(shù),返回的函數(shù)接收state與action兩個變量七蜘。在官方手冊給的用法谭溉,combineReducer之后是直接可以作為參數(shù)傳入給createStore(具體分析見Redux源碼閱讀_1(上))來生成store的,但是源碼的返回值卻是個函數(shù)橡卤,這是怎么回事扮念?
帶著這個問題繼續(xù)看……
函數(shù)體內(nèi)聲明的變量定義了兩種特殊的類型,ReducersMapObject和StateFromReducersMapObject碧库,看看這兩種類型的定義柜与。
export type Reducer<S = any, A extends Action = AnyAction> = (
state: S | undefined,
action: A
) => S
export type ReducersMapObject<S = any, A extends Action = AnyAction> = {
[K in keyof S]: Reducer<S[K], A>
}
export type StateFromReducersMapObject<M> = M extends ReducersMapObject
? { [P in keyof M]: M[P] extends Reducer<infer S, any> ? S : never }
: never
可以看到:
Reducers是入?yún)閟tate與action,且返回一個state的函數(shù)(state類型為S)瓦呼。
ReducersMapObject是value值為Reducer類型的Object栓辜。(之前以為ReducerMapObject是key值為state恨豁,value值為Reducer類型的Map,看了發(fā)現(xiàn)命名不太對迁匠。。定義的key是[K in keyof S]秕脓,state 為 S 類型柒瓣,而我們定義的state又是Object,那state的key就是string吠架,那么ReducerMapObject的key也是string類型芙贫,所以他應(yīng)該是個Object,而不是Map)
StateFromReducersMapObject是value值為是state的Object(之前以為類型是key值為Reducer類型傍药,value為state的Map磺平,但是定義的M繼承自ReducersMapObject,那么 M 的 key 類型為 string拐辽,那么 P 類型就是 string拣挪,所以他的類型應(yīng)該是Object而不是Map)。
現(xiàn)在就可以回答上面的問題了俱诸,combineReducers返回一個接受state與action的函數(shù)菠劝,而redux里定義的reducer也是這樣的一個函數(shù),所以combineReducers的返回值類型其實就是一個Reducer……(被自己蠢到了睁搭,因為想看源碼就把ts快速過了一遍赶诊,類型這一塊剛看有點懵,看源碼的時候一直在糾結(jié)這個變量是啥類型园骆、那個變量是啥類型的問題舔痪。。)
函數(shù)實現(xiàn)
combineReducers函數(shù)內(nèi)部主要操作:
- 將value類型為function的所有reducers復(fù)制到finalReducers
- 返回combine函數(shù)
combine函數(shù)的操作:
- 新建 nextState : StateFromReducersMapObject<typeof reducers> 變量
- 遍歷finalReducers锌唾,計算當(dāng)前state與nextState值锄码,并將nextState賦值給對應(yīng)key值的nextState,修改hasChanged標(biāo)識變量的值
- 根據(jù)hasChanged標(biāo)識變量確定是返回傳入?yún)?shù)state還是新建變量nextState
由combine函數(shù)操作可知,redux返回的state都是全新的state滋捶,而不是在之前的state上做修改痛悯,其內(nèi)存地址有變化
具體代碼如下:
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
}
}