export { createStore, //建立一個state用來存儲狀態樹 combineReducers, //合併reducer bindActionCreators, //將dispatch和action結合 applyMiddleware, //調度中間件來加強store,例如中間件redux-thunk等 compose //從右向左組合多個函數, compose(f, g, h)會返回(...args) => f(g(h(...args))) }
Redux源碼結構和提供的API大致對應,以下:
utils——warning.js //console中打印warning信息要用到的
applyMiddleware.js
bindActionCreators.js
combineReducers.js
compose.js
createStore.js
index.js //export 上述定義的moduleredux
上面咱們看到了redux的API和源碼結構,看的出來,warning.js和index.js不用解析,都看得懂,關鍵時其他的幾個module,那咱們從最重要的createStore講起。數組
export var ActionTypes = { INIT: '@@redux/INIT' } //首先定義了一個action類型,咱們知道更新state的惟一方法就是dispatch一個action,這個action是用 // 來初始化state的,後面會用到它
如今來看下createStore的大致結構app
//接收三個參數 //reducer爲function。當dispatch一個action時,此函數接收action來更新state //preloadState初始化State //enhancer 爲function。用來加強store, Redux 定義有applyMiddleware來加強store,後面會 //單獨講applyMiddleware export default function createStore(reducer, preloadedState, enhancer) { if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { //若是隻傳了兩個參數,而且第二個參數爲函數,第二個參數會被看成enhancer enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { //校驗enhancer是否爲函數,若是不是函數則拋出異常 throw new Error('Expected the enhancer to be a function.') } //若是enhancer存在且爲函數,那麼則返回以下調用,若是enhancer爲applyMiddleware,那麼調用則 //是applyMiddleware(middleware1, middleware2, middleware3...)(createStore)(reducer, preloadedState)。後面講applyMiddleware再詳細講。 return enhancer(createStore)(reducer, preloadedState) } if (typeof reducer !== 'function') { //校驗reducer是否爲函數 throw new Error('Expected the reducer to be a function.') } var currentReducer = reducer //獲得reducer var currentState = preloadedState //獲得初始init,沒有傳遞則爲undefined var currentListeners = [] //定義一個數組用來存放listeners。就是一個函數數組,當state發生改變時,會循環執行這個數組裏面的函數 var nextListeners = currentListeners //用來存儲下一次的listeners數組。爲何要有這個listeners數組呢?由於當state發生改變時,咱們根據 //上面的currentListeners來循環執行函數,可是在這執行這些函數時,函數內部可能取消或者添加訂閱 //(state改變時,添加或者取消執行函數),這時若是直接操做currentListeners ,至關於在循環 //內部修改循環條件,執行瞬間就亂套了,有沒有啊,有沒有 var isDispatching = false //reducer函數是否正在執行的標識 function ensureCanMutateNextListeners() { //拷貝currentListeners一份爲nextListeners,這樣nextListeners的改變不會引發currentListeners的改變 //(上面解釋過緣由啦) } function dispatch() { //觸發action去執行reducer,更新state ..... } function subscribe() { //接收一個函數參數,訂閱state的改變。當state改變時會執行這個函數 .... } function getState() { //獲取state樹 .... } function replaceReducer() { //替換reducer .... } function observable() { //沒用,不解釋(後面有解釋) ...... } dispatch({ type: ActionTypes.INIT }) //執行dispatch函數,初始化state return { //真正的返回,執行createStore其實返回的就是這些東東 dispatch, //觸發action去執行reducer,更新state subscribe, //訂閱state改變,state改變時會執行subscribe的參數(本身定義的一個函數) getState, //獲取state樹 replaceReducer, //替換reducer [$$observable]: observable //redux內部用的,對咱們來講沒用(非要深究它寫這是幹嗎的?咋跟 //我同樣死腦筋呢,都說了沒用啦。算了,仍是告訴你把,就是內部用的,在測試代碼中會用到,感興 //趣的能夠去test目錄下查看) } }
如今是否是感受明朗(懵逼)了許多,懵逼就對了,接下來咱們再來解析一下dispatch, subscribe等函數的具體實現,或許會讓你明朗(更懵逼)起來
看了上面的大致結構,咱們明白如下這些就夠了。
createStore是一個函數,它定義了一些變量(currentState, currentListeners等)及函數(dispatch, subscribe等),而且調用了dispatch,最後返回一個對象,該對象包含的就是dispatch和subscribe等函數。接下來咱們來解析這些函數。
createStore裏面只調用了一個函數,那就是dispatch,那咱們就從這裏開始講起。異步
它是這樣被調用的,有沒有很熟悉。。。async
dispatch({ type: ActionTypes.INIT })
來看看dispatch的源碼函數
function dispatch(action) { //校驗action參數,必須爲一個純粹的對象。這也說明了,咱們不能直接在redux作異步請求,而是須要 //使用applyMiddleware去應用一些中間件。好比redux-thunk等 if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } //一樣是校驗參數,不解釋,相信都能看懂 if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } //判斷是否正在執行reducers函數,若是正在執行,此action不會觸發,那有人就問題了,那是否是我 //的dispatch不會起做用,致使state沒有更新,數據是錯誤的? 答案是state是不會有錯。由於redux本 //身整個更新state的過程是同步的,從dipatch——>reducers——>state。因此這段代碼意在你定義的 //reducers函數中不容許調用dispatch if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } try { //設置標識爲true,而且執行currentReducer,還記得嗎?這個咱們經過參數獲取到的一個函數,每每是我 //們調用combineReducers返回,combineReducers咱們後面解析 isDispatching = true //調用reducers函數 currentState = currentReducer(currentState, action) } finally { isDispatching = false } //調用全部訂閱state改變的函數,這些函數就能夠經過getState函數獲取到最新的state值。訂閱的函數 //從哪裏來呢,從subscribe中來, 咱們後面來解析subscribe和getState var listeners = currentListeners = nextListeners for (var i = 0; i < listeners.length; i++) { listeners[i]() } return action }