Redux官方代碼庫(kù)提供了以下幾個(gè)模塊文件:
applyMiddleware.js
bindActionCreators.js
combineReducers.js
compose.js
createStore.js
compose.js
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for
* the resulting composite function.
*
* @param {...Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing the argument functions
* from right to left. For example, compose(f, g, h) is identical to doing
* (...args) => f(g(h(...args))).
*/
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)))
}
以上代碼很好理解兼搏,當(dāng)compose無(wú)參數(shù)時(shí),返回一個(gè)空函數(shù),參數(shù)為唯一函數(shù)時(shí),直接將這個(gè)函數(shù)作為返回值,重點(diǎn)在于最后一部分:
return funcs.reduce((a, b) => (...args) => a(b(...args)))
對(duì)多個(gè)參數(shù)組合成的函數(shù)數(shù)組進(jìn)行reduce操作杭跪,其實(shí)以上代碼等同于:
return funcs.reduceRight((composed, f) => f(composed));
相當(dāng)于對(duì)數(shù)組內(nèi)的所有函數(shù),從右至左,將前一個(gè)函數(shù)作為后一個(gè)函數(shù)的入口參數(shù)依次返回教硫,比如compose(fn1,fn2,fn3)最后返回的結(jié)果應(yīng)該是這樣子的:
fn1(fn2(fn3))
bindActionCreators.js
import warning from'./utils/warning'
function bindActionCreator (actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args))
}
export default function bindActionCreators (actionCreators, dispatch) {
if (typeof actionCreators ==='function') {
return bindActionCreator(actionCreators, dispatch)
}
if (typeof actionCreators !=='object'|| actionCreators ===null) {
throw new Error(`bindActionCreators expected an object or a function, instead received ${actionCreators === null ? 'null' : typeof actionCreators}. ` + `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`)
}
const keys = Object.keys(actionCreators)
const boundActionCreators ={}
for (let i =0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator ==='function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
} else {
warning(`bindActionCreators expected a function actionCreator for key '${key}', instead received type '${typeof actionCreator}'.`)
}
}
return boundActionCreators
}
對(duì)于單個(gè)actionCreator,代碼很簡(jiǎn)單辆布,直接返回一個(gè)被dispatch包裹過(guò)的action而已瞬矩,對(duì)于多個(gè)actionCreators,如果入口參數(shù)是一個(gè)function谚殊,說(shuō)明只提供了一個(gè)actionCreator丧鸯,直接調(diào)用bindActionCreator(actionCreators,dispatch),對(duì)于以對(duì)象形式輸入的多個(gè)actionCreators嫩絮,對(duì)其遍歷輸出每一個(gè)bindActionCreator(actionCreators,dispatch)并封裝在具有同名鍵值的boundActionCreators對(duì)象中丛肢,這樣在我們需要調(diào)用action的地方直接boundActionCreators[actionCreate定義名]就可以了。
createStore.js
//用于校驗(yàn)是否是純對(duì)象
import isPlainObject from'lodash/isPlainObject'
//內(nèi)部私有屬性剿干,暫時(shí)不做擴(kuò)展
import $$observable from'symbol-observable'
//內(nèi)部action,用于調(diào)用所有reducers生成初始state
export const ActionTypes ={INIT:'@@redux/INIT'}
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof preloadedState ==='function' && typeof enhancer ==='undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !=='undefined') {
if (typeof enhancer !=='function') {
throw new Error('Expected the enhancer to be a function.')
}
//函數(shù)柯里化蜂怎,enhancer提供增強(qiáng)版(中間件擴(kuò)展)的store
return enhancer(createStore)(reducer, preloadedState)
}
//reducer必須是一個(gè)function
if (typeof reducer !=='function') {
throw new Error('Expected the reducer to be a function.')
}
//store內(nèi)部私有變量(外部無(wú)法直接訪問(wèn))
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
//為下一階段監(jiān)聽(tīng)器快照提供備份
function ensureCanMutateNextListeners () {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
//獲取最新state
function getState() {
return currentState
}
//用于訂閱state的更新
function subscribe(listener) {
if (typeof listener !=='function') {
throw new Error('Expected listener to be a function.')
}
//保證只有第一次執(zhí)行unsubscribe()才是有效的,只取消注冊(cè)當(dāng)前l(fā)istener
let isSubscribed =true
//為每次訂閱提供快照備份nextListeners置尔,主要防止在遍歷執(zhí)行currentListeners回調(diào)
//過(guò)程中觸發(fā)了訂閱/取消訂閱功能杠步,若直接更新currentListeners將造成當(dāng)前循環(huán)體邏輯混亂
//因此所有訂閱/取消訂閱的listeners都是在nextListeners中存儲(chǔ)的,并不會(huì)影響當(dāng)前的dispatch(action)
ensureCanMutateNextListeners()
nextListeners.push(listener)
//返回一個(gè)取消訂閱的函數(shù)
return function unsubscribe() {
//保證當(dāng)前l(fā)istener只被取消注冊(cè)一次
if (!isSubscribed) { return }
isSubscribed =false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index,1)
}
}
function dispatch(action) {
//保證dispatch是個(gè)純對(duì)象榜轿,即字面量對(duì)象或Object創(chuàng)建的對(duì)象
//這是因?yàn)樵及娴膁ispatch只支持同步action幽歼,約定的格式是純對(duì)象
//可以使用中間件來(lái)dispatch擴(kuò)展功能,增加action的類型種類
if (!isPlainObject(action)) {
throw new Error('Actions must be plain objects. '+'Use custom middleware for async actions.')
}
//action必須要有key為type的動(dòng)作類型
if (typeof action.type ==='undefined') {
throw new Error('Actions may not have an undefined "type" property. '+'Have you misspelled a constant?')
}
//判斷在執(zhí)行dispatch的過(guò)程中是否已存在dispatch的執(zhí)行流
//保證dispatch中對(duì)應(yīng)的reducer不允許有其他dispatch操作
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
//根據(jù)提供的action谬盐,執(zhí)行根reducer從而更新整顆狀態(tài)樹(shù)
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
//通知所有之前通過(guò)subscribe訂閱state更新的回調(diào)listener
const listeners = currentListeners = nextListeners
for(let i =0; i < listeners.length; i++) {
const listener = listeners[i]listener()
}
return action
}
//替換當(dāng)前reducers甸私,如從其他文件引入了新的reducers進(jìn)行熱加載
function replaceReducer (nextReducer) {
if (typeof nextReducer !=='function') {
throw new Error('Expected the nextReducer to be a function.')
}
}
function observable () {
const outerSubscribe = subscribe
return {
subscribe (observer) {
if (typeof observer !=='object') {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable] () {
return this
}
}
}
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
一眼望去,還是有些懵逼的飞傀,但如果我們把它劃分為以下三個(gè)部分分別理解或許就簡(jiǎn)單多了皇型。
- 入口參數(shù):reducer、preloadState砸烦、enhancer
- 內(nèi)部變量:currentReducer弃鸦、currentState、currentListeners幢痘、nextListeners唬格、isDispatching
- 輸出:dispatch、subscribe、getState西轩、replaceReducer