redux的createStore第二引數preloadedState(初始化state)是如何控制單一或通過combineReducer組合生成的reducer中手動加的state的預設值是否生效的

o小紅帽o發表於2019-08-22

createStore中的第二個引數preloadedState是可選的,如果省略第二個引數preloadedState,直接設定第三個引數composeEnhancers(用於新增中介軟體的),那麼createStore內部會進行處理,將preloadedState設定為undefined。或者第二個引數和第三個引數都沒有的話,preloadedState也是undefined
const store = createStore(reducerz,{a:55555},composeEnhancers(
applyMiddleware(thunk)
));
createStore()函式執行時會先在內部進行一次初始化的dispatch,來使state有一個初始值,這個初始化的過程中會 將preloadedState、單一reducer或者combineReducer生成的reducer、reducer中的引數state的預設值三者之間進行處理,得出一個初始化的state。

1.單一reducer:
<1> 有preloadedState:
const store = createStore(reducer1,{open:55555},composeEnhancers(
applyMiddleware(thunk)
));
reducer1 = (state={count:0},action)=>{
}
上例中的preloadedState = {open:55555}這個引數,那麼preloadedState會在初始化的過程中出入reducer1中,從而覆蓋掉reducer1中引數state的預設值{count:0},使得reducer1中的state初始化時為 {open:55555}。
<2> 無preloadedState:
const store = createStore(reducer1,composeEnhancers(
applyMiddleware(thunk)
));
reducer2 = (state={count:0},action)=>{
}
上例中的preloadedState = undefined,那麼createStore在初始化的過程中顯式的將一個undefined傳入reducer1中,根據es6函式引數的預設值相關知識可以知道,當顯式的傳入undefined時 ,引數state的預設值{count:0}會生效,使得reducer1中的state初始化時為 {count:0}。
2. combineReducer()多個reducer混合
reducer = combineReducers({a:reducer1,b:reducer2})
combineReducers的原理:
combineReducers = reducers => {
return (state = {}, action) => {
return Object.keys(reducers).reduce(
(nextState, key) => {
nextState[key] = reducers[key](state[key], action);
return nextState;
},
{}
);
};
};
所以生成的reducer是一個函式,這個函式返回的是一個包含各個key的大state。
<1> 有preloadedState:
const store = createStore(reducer,{a:{count:11}},composeEnhancers(
applyMiddleware(thunk)
));
reducer1 = (state={count:0},action)=>{
}
reducer2 = (state={count:0},action)=>{
}
有preloadedState時,preloadedState中的key必須與combineReducers中傳入的物件的key一樣,否則通過combineReducers的原理我們可以看到這個preloadedState還是不會覆蓋掉各個子reducer中的state的。
preloadedState會首先替換combineReducers()生成的大的reducer中state設定的預設值空物件{},然後通過combineReducers()中傳入的物件的key在 preloadedState找,看preloadedState有沒有這個key,如果有的話,就會將preloadedState中的這個key的所對應的值傳入到對應的子reducer中,從而將子reducer中的state的預設值替換掉。如果preloadedState中沒有這個key,那麼傳入子reducer中的就是undefined,那麼子reducer中state的預設值就會生效。
上例中我們的preloadedState是{a:{count:11}},那麼初始化中會將子reducer1中的state預設值替換掉,換為{count:11},而子reducer2還是原始的預設state {count:0},因為preloadedState中並沒有b這個key,所以從combineReducers原理中可以看到傳入子reducer2中的state[key]是一個undefined。
<2> 無preloadedState:
通過<1>中可以看到,如果沒有preloadedState,那麼combineReducers()生成的那個大的reducer中自帶的state的預設值空物件{}就會生效,繼而在初始化時,依次在空物件中找相應的key,空物件肯定是沒有這個key的,所以初始化時所有的子reducer都是會使用其state設定的那個預設值。
<3>preloadedState為空物件{},那麼combineReducers()生成的那個大的reducer中自帶的state的預設值空物件{}就會被preloadedState為空物件{}替換,繼而在初始化時,依次在空物件中找相應的key,空物件肯定是沒有這個key的,所以初始化時所有的子reducer都是會使用其state設定的那個預設值。<2>和<3>意思差不多。

https://www.cntofu.com/book/4/docs/recipes/reducers/InitializingState.md

相關文章