本文不講 react、redux、action、reducer 的具體應用,只是單純的講解 reducer 爲何必須是純函數,本文適合有必定 redux 開發經驗的同窗。javascript
用過 react 的同窗對 redux 必定不會陌生,咱們知道 redux 能夠提供可預測化的狀態管理。在一個應用中,全部的 state 都是以一個對象樹的形式存在一個單一的 store 中,惟一改變 state 的辦法就是觸發 action,而 reducer 就是用來編寫專門的函數決定每一個 action 如何改變應用的 state 。java
如官網所說,reducer 就是一個純函數,接受舊的 state 和 action,返回新的 state (previousState, action) => newState
react
咱們的疑問來了:redux
爲何reducer 必須是一個純函數?
爲何必須返回一個新的 state?
返回舊的 state 爲何不行?
redux 源碼是怎麼寫的?函數
咱們首先來看下正常案例,咱們通常會有以下幾種寫法返回新state:性能
在 Redux store 中保存了 reducer 返回的 這個 state,這個新的 store 樹就是應用的下一個 state, 全部訂閱 store.subscribe(listener)
的監聽器都將被調用,監聽器裏能夠調用 store.getState()
得到當前 state 此時,咱們就可使用新的 state 來更新 UI setState(newState)
設計
這裏簡單的講解一下什麼是純函數?3d
咱們先來試驗下,若是 reducer 不是純函數會發生什麼? 咱們將上面代碼reducer改造一下,直接修改 state,而不是返回新的 statecode
改變代碼後,咱們發現當咱們觸發了 action 之後,頁面沒有發生任何變化,這是爲何呢?cdn
咱們來看下 redux 源碼:
經過源代碼,咱們發現,var nextStateForKey = reducer(previousStateForKey, action)
, nextStateForKey就是經過 reducer 執行後返回的結果(state),而後經過hasChanged = hasChanged || nextStateForKey !== previousStateForKey
來比較新舊兩個對象是否一致,此比較法,比較的是兩個對象的存儲位置,也就是淺比較法,因此,當咱們 reducer 直接返回舊的 state 對象時,Redux 認爲沒有任何改變,從而致使頁面沒有更新。
由於比較兩個 javascript 對象中全部的屬性是否徹底相同,惟一的辦法就是深比較,然而,深比較在真實的應用中代碼是很是大的,很是耗性能的,須要比較的次數特別多,因此一個有效的解決方案就是作一個規定,當不管發生任何變化時,開發者都要返回一個新的對象,沒有變化時,開發者返回就的對象,這也就是 redux 爲何要把 reducer 設計成純函數的緣由。