整個redux的原始碼非常簡單,所以解釋很少,看程式碼就能看明白......
combineReducers
為啥先說這個
前提先看middleware: Redux-Middleware-原始碼解析, 這些都是解析createStore的前提
//傳入的reducers是個物件
//將多個reducer捆成一個
export default function combineReducers(reducers) {
//取出所有reducer的key=> {key1:value,key2:value}
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
//取出key
const key = reducerKeys[i]
if (typeof reducers[key] === 'function') {
//可以代表的value是函式的話,儲存進 finalReducers 物件中
finalReducers[key] = reducers[key]
}
}
//取出所有value是函式的key
const finalReducerKeys = Object.keys(finalReducers)
let shapeAssertionError
try {
assertReducerShape(finalReducers)
} catch (e) {
shapeAssertionError = e
}
//返回一個 combination 函式,方法接收state,action引數 這個返回的函式是createStore的第一個引數
return function combination(state = {}, action) {
if (shapeAssertionError) {
throw shapeAssertionError
}
let hasChanged = false
const nextState = {}
//迴圈每一個reducer,
for (let i = 0; i < finalReducerKeys.length; i++) {
//取出key
const key = finalReducerKeys[i]
//取出key對應的reducer
const reducer = finalReducers[key]
//根據key在state獲取狀態
//state的狀態都是根據reducer的名字進行儲存的
const previousStateForKey = state[key]
//將state和action傳入reducer中
const nextStateForKey = reducer(previousStateForKey, action)
//將nextStateForKey reducer 放入到nextState中
nextState[key] = nextStateForKey
//在state中的狀態和reducer中返回的狀態是否一樣
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
//返回新的state
return hasChanged ? nextState : state
}
}
複製程式碼
是什麼
- 名字的含義就是組合reducer
- 因為reducers是作為createStore函式的第一個引數,而不是前多少個引數
幹了什麼
export default combineReducers({
userinfo,
stores,
home,
likeList
})
複製程式碼
- 其中的每一個引數都是一個reducer,而且每一個引數的名字都作為在store中的key
- 將這些reducer組合成一個reducers,提供給createStore作為引數
流程啥樣
- 雖然傳了很多reducer但是先過濾掉不是function的reducer(不知道不是function的reducer是啥)
- 將過濾的key存放到finalReducerKeys中,將過濾的reducer存放到finalReducers中,閉包要用
- 然後返回一個 combination() 函式,其實這個才是createStore的第一個引數
combination做了什麼
- 迴圈每一個有效的reducer
- 取出reducer,state中的對應的狀態
- 呼叫reducer,並傳入取出的狀態,和action,獲取返回值(新state)
- 返回新的state
createStore
//建立store的api,也是redux中最重要的api,而建立的store用於管理應用中的所有state,且只有一個store
export default function createStore(reducer, preloadedState, enhancer) {
//簡而言之,第二個引數是函式,並且第三個引數是undefined,然後第二第三個引數值互換
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
//這個就是中介軟體,看middleware那篇文章
return enhancer(createStore)(reducer, preloadedState)
}
//儲存當前的reducer
let currentReducer = reducer
//儲存傳入的狀態
let currentState = preloadedState
//設定當前監聽集合
let currentListeners = []
//將當前的監聽集合賦值給下一個監聽集合
let nextListeners = currentListeners
let isDispatching = false
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
//slice() 沒有引數預設begin為0 就是拷貝下
nextListeners = currentListeners.slice()
}
}
//獲取當前狀態
//函式巢狀函式,內部函式引用外部函式的變數,最後返回函式,這是閉包
function getState() {
return currentState
}
//增加監聽,引數listener是一個回撥函式,在dispatch裡,會呼叫所有的監聽器
function subscribe(listener) {
let isSubscribed = true
ensureCanMutateNextListeners()
//把新增加的監聽加入到當前監聽列表中
nextListeners.push(listener)
//返回一個函式,用於去除監聽
return function unsubscribe() {
if (!isSubscribed) {
return
}
//解除監聽 isSubscribed 設定為false,意為已經取消監聽
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
//然後幹掉這個監聽
nextListeners.splice(index, 1)
}
}
//這個是比較常用的api=>主要用於觸發action,改變狀態
function dispatch(action) {
try {
isDispatching = true//正在dispatch
//執行reducer 返回新state,呼叫的是combination()方法
currentState = currentReducer(currentState, action)
} finally {
// finally不管報沒報錯最後都要執行
isDispatching = false
}
//執行所有監聽
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
//替換reducer 然後更新store
function replaceReducer(nextReducer) {
currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE })
}
//這個是留給內部
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this
}
}
}
//初始化store
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
複製程式碼
是什麼
- 這個是最核心的api,這個函式是建立store的唯一方式
- 並且返回了dispatch,subscribe,getState...比較常用的api
幹了什麼
const store = createStore(rootReducer, applyMiddleware(...middlewares));
複製程式碼
- 如果有中介軟體,先處理中介軟體然後回過頭來在執行createStore
- 儲存了一些當前的屬性,用於閉包,提供的api
api
getState
這個直接返回了當前的state,因為閉包,所以可以獲取到最新的state
subscribe
負責新增監聽,引數是個回撥函式,將回撥函式加入到監聽集合,並且返回一個取消監聽的函式:這個返回的函式內部封裝了當執行時,在監聽集合中將這個監聽去掉
dispatch
是最核心的api,通過執行reducer(閉包,currentReducer),返回新的state,並賦值給當前的currentState,並執行所有的監聽,返回action
replaceReducer
用於替換reducer,然後呼叫dispatch更新state
bindActionCreators
這個結合connect使用,在mapDispatchToProps中定義,就可以直接用this.props.userInfoActions來呼叫dispatch(action)操作
function mapStateToProps( state ) {
return {}
}
function mapDispatchToProps( dispatch ) {
return {
userInfoActions : bindActionCreators(userInfoActionsFormOtherFile, dispatch)
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App)
複製程式碼
function bindActionCreator(actionCreator, dispatch) {
return function() {
return dispatch(actionCreator.apply(this, arguments))
}
}
export default function bindActionCreators(actionCreators, dispatch) {
//如果 actionCreators 是一個函式,染回 dispatch(actionCreator.apply(this, arguments))
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
//actionCreators 不是函式,不是物件,不是null
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
//最後迭代actionCreators裡的元素,如果是函式,就按照函式的方式組成陣列,返回
return boundActionCreators
}
複製程式碼
是什麼
就跟名字一樣:給actionCreators繫結dispatch,也就是返回一個dispatch(actionCreator.apply(this, arguments))這樣的函式,或者包含多個dispatch的陣列
幹了什麼
- 傳入兩個引數,第一個是actionCreator,第二個是dispatch
- 如果只是一個actionCreator,那麼直接返回一個包含dispatch(actionCreator.apply(this, arguments))的函式
- 如果他是個陣列,就去迴圈這個陣列將每一個actionCreator都繫結dispatch,然後返回這個陣列
總結
看完了原始碼,感覺redux真的沒有太多的東西,真是對映了那句話:用盡量少的程式碼,做盡量多的事情!
combineReducers
- 引數reducers是一個多個reducer組合的物件
- 去除所有的reducer的key=> reducerKeys
- 迴圈reducerKeys通過key取出reducer
- 如果reducer是個函式,就加進 finalReducers 中
- 取出finalReducers中的所有key=>finalReducerKeys
- 然後返回combination,這個是個內部函式,裡面用到了上面的finalReducers和finalReducerKeys
- combination中取出每個reducer,根據finalReducerKeys中對應的key,在state中取出響應的狀態
- 執行reducer並將引數傳入返回新狀態
- 將返回的狀態新增進nextState物件中
- 返回新狀態
通過程式碼的執行總結combineReducers
- 將多個reducer的物件reducers傳入combineReducers中
- 返回 combination函式
- 返回的函式作為createStore的第一個引數
- 進入createStore中,提供的dispatch()中用到了reducers,並傳入了state和action
- 然後執行combination函式,迴圈finalReducers
- 執行每一個reducer,通過返回的state,並新增進nextState物件中
- 返回的state和引數的state比較,如果兩個state相等,則說明這個key所對應的state沒有變化
- 如果不相等說明有變化,標記有變化
- 最後根據state是否有變化決定返回 nextState 還是引數 state