redux
是狀態管理庫,與其餘框架如 react
是沒有直接關係,因此 redux
能夠脫離 react
在別的環境下使用。因爲沒有和react
相關邏輯耦合,因此 redux
的源碼很純粹,目的就是把如何數據管理好。而真正在 react
項目中使用 redux
時,是須要有一個 react-redux
看成鏈接器,去鏈接 react
和 redux
。html
沒看 redux
源碼以前,我以爲看 redux
應該是件很困難的事情,由於當初在學 redux
如何使用的時候就已經被 redux
繁多的概念所淹沒。真正翻看 redux
源碼的時候,會發現 redux
源碼內容至關之少,代碼量也至關少,代碼質量也至關高,因此是很是值得看的源碼。react
其餘目錄均可以不看,直接看 ./src
吧:git
.REDUXSRC
│ applyMiddleware.js
│ bindActionCreators.js
│ combineReducers.js
│ compose.js
│ createStore.js
│ index.js
│
└─utils編程
actionTypes.js isPlainObject.js warning.js
index.js
就是把 applyMiddleware.js
等聚集再統一暴露出去。utils
裏面就放一些輔助函數。因此一共就五個文件須要看,這五個文件也就是 redux
暴露出去的五個 API
。redux
// index.js import createStore from './createStore' import combineReducers from './combineReducers' import bindActionCreators from './bindActionCreators' import applyMiddleware from './applyMiddleware' import compose from './compose' import warning from './utils/warning' import __DO_NOT_USE__ActionTypes from './utils/actionTypes' // 忽略內容 export { createStore, combineReducers, bindActionCreators, applyMiddleware, compose, __DO_NOT_USE__ActionTypes }
這是五個 API
裏惟一一個能單獨拿出來用的函數,就是函數式編程裏經常使用的組合函數,和 redux
自己沒有什麼多大關係,先了解下函數式編程的一些概念:數組
純函數是這樣一種函數,即相同的輸入,永遠會獲得相同的輸出,並且沒有任何可觀察的反作用。
代碼組合
代碼:app
export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args))) }
其實 compose
函數作的事就是把 var a = fn1(fn2(fn3(fn4(x))))
這種嵌套的調用方式改爲 var a = compose(fn1,fn2,fn3,fn4)(x)
的方式調用。框架
redux
的 compose
實現很簡潔,用了數組的 reduce
方法,reduce
的用法能夠參照 mdn。ide
核心代碼就一句:return funcs.reduce((a,b) => (..args) => a(b(...args)))
函數式編程
我雖然常常寫 reduce
函數,可是看到這句代碼仍是有點懵的,因此這裏舉一個實際的例子,看看這個函數是怎麼執行的:
import {compose} from 'redux' let x = 10 function fn1 (x) {return x + 1} function fn2(x) {return x + 2} function fn3(x) {return x + 3} function fn4(x) {return x + 4} // 假設我這裏想求得這樣的值 let a = fn1(fn2(fn3(fn4(x)))) // 10 + 4 + 3 + 2 + 1 = 20 // 根據compose的功能,咱們能夠把上面的這條式子改爲以下: let composeFn = compose(fn1, fn2, fn3, fn4) let b = composeFn(x) // 理論上也應該獲得20
看一下 compose(fn1, fn2, fn3, fn4)
根據 compose
的源碼, 其實執行的就是:[fn1,fn2,fn3.fn4].reduce((a, b) => (...args) => a(b(...args)))
第幾輪循環 | a的值 | b的值 | 返回的值 |
---|---|---|---|
第一輪循環 | fn1 | fn2 | (...args) => fn1(fn2(...args)) |
第二輪循環 | (...args) => fn1(fn2(...args)) | fn3 | (...args) => fn1(fn2(fn3(...args))) |
第三輪循環 | (...args) => fn1(fn2(fn3(...args))) | fn4 | (...args) => fn1(fn2(fn3(fn4(...args)))) |
循環最後的返回值就是 (...args) => fn1(fn2(fn3(fn4(...args))))
。因此通過 compose
處理過以後,函數就變成咱們想要的格式了。
compose
函數在函數式編程裏很常見。這裏 redux
的對 compose
實現很簡單,理解起來卻沒有那麼容易,主要仍是由於對 Array.prototype.reduce
函數沒有那麼熟練,其次就是這種接受函數返回函數的寫法,再配上幾個連續的 =>
,容易看暈。
這是 redux
解讀的第一篇,後續把幾個 API
都講一下。特別是 applyMiddleware
這個 API
有用到這個 compose
來組合中間件,也是有那麼一個點比較難理解。