reducer是redux的三個核心概念之一,它指定了應用狀態的變化如何響應 actions 併發送到 store,須要由開發人員本身定義,提起reducer,最常想到的一個準則是reducer要是純函數,那麼這其中是什麼緣由呢,若是不是純函數的話會致使redux不可用嗎?接下來就來一步步分析下這個問題react
咱們定義的reducer負責接收action,並返回一個新的state,但在react組件開發中,咱們也僅僅定義了而從未實際調用過reducer,全部reducer做用的原理是什麼呢?redux
實際上,組件中咱們會手動調用dispatch方法發送action來響應事件,而這裏的發送action不止發送action那麼簡單,還包括了調用reducer,更新狀態爲reducer的處理結果,觸發訂閱事件等一系列操做,都是在dispatch的方法內實現的,到這裏能夠來經過源碼的處理流程來了解一些這個過程~api
function dispatch(action) {
...
try {
//將flag置爲true,代表處於分發邏輯中
isDispatching = true
//currentReducer即爲傳入的reducer函數,這裏會自動調用currentReducer函數,並將返回值賦給currentState
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//調用訂閱函數
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
複製代碼
能夠看到,dispatch處理中reducer方法的調用無疑是很關鍵的一步,通過它的處理以後才生成了新的狀態數據 在redux中,保持reducer是一個純函數很是重要,保證reducer是純函數要達到如下幾點:promise
那麼爲何reducer函數要遵照這幾點規則呢,若是不遵照的話又會怎麼樣呢bash
function reuderfunc(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return ...
default:
return state
}
}
複製代碼
reducer接受的參數由兩個,一個是action
,一個是state
,其中action
只是用來傳遞信息的,徹底沒有修改的必要,那麼state
呢,既然reducer
是用來返回一個新的state
的,在這個過程當中直接基於傳入的state
來改,而後再返回,貌似也能夠達到效果? 實際上,雖然在reducer處理過程當中改變了傳入的state,有可能redux還會正常運轉,但像時間旅行,錄製和回放這類依賴於歷史狀態的功能則沒法實現了,要知道這但是redux當時的設計初衷之一~ 特別注意的是,若是改變了傳入的參數initState,或該對象底層的任意一個key值,都有可能在應用於react組件時,致使react任爲該狀態無變化,而不更新組件,由於redux源代碼中將oldState和newState(reducer返回的結果)作比較,若是某一級state指定的引用相等,則會致使此結果,這樣作是犧牲一點計算性能(生成新對象)來保證頁面刷新。併發
redux的核心提供可預測化的狀態管理,即不管什麼時候特定的action觸發的行爲永遠保持一致,試想若是reducer中有Date.now()等非純函數,即便一樣的action,那麼reducer處理過程當中也是有所不一樣的,再也不能保證可預測性dom
首先,執行有反作用的操做,如api和路由跳轉,由於設置到後臺的處理,會帶來和上一節一樣的問題,一樣的action觸發後的處理過程可能有所不一樣(依據後臺處理或路由跳轉而定),失去了可預測性 其次由於reducer函數的返回值是要做爲下一個狀態值被返回的,那麼試想當reducer中有api調用時,api是會向後臺請求數據的異步函數,每每但願後臺的請求結果數據會應用於新的state,可是這時候會發現,這個異步函數卸載reducer中沒有辦法影響到state的更新,由於在異步請求處理完成時,reducer函數已經被返回(函數的返回是同步的),因此說在redcuer中調用api也徹底沒有意義了.異步
剛纔提到在reducer中不能執行api請求操做,可是很明顯api操做是不可避免的,由於總要向後臺請求數據,那麼api請求應該如何作呢?這裏有兩個辦法函數