redux
是狀態管理庫,與其餘框架如 react
是沒有直接關係,因此 redux
能夠脫離 react
在別的環境下使用。因爲沒有和react
相關邏輯耦合,因此 redux
的源碼很純粹,目的就是把如何數據管理好。而真正在 react
項目中使用 redux
時,是須要有一個 react-redux
看成鏈接器,去鏈接 react
和 redux
。html
沒看 redux
源碼以前,我以爲看 redux
應該是件很困難的事情,由於當初在學 redux
如何使用的時候就已經被 redux
繁多的概念所淹沒。真正翻看 redux
源碼的時候,會發現 redux
源碼內容至關之少,代碼量也至關少,代碼質量也至關高,因此是很是值得看的源碼。react
其餘目錄均可以不看,直接看 ./src
吧:git
.\REDUX\SRC │ 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
自己沒有什麼多大關係,先了解下函數式編程的一些概念:數組
代碼:框架
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)
的方式調用。ide
redux
的 compose
實現很簡潔,用了數組的 reduce
方法,reduce
的用法能夠參照 mdn。函數式編程
核心代碼就一句: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
來組合中間件,也是有那麼一個點比較難理解。