前言
Redux 源碼的體量算是比較小的了,但是詳細(xì)解讀還是有點(diǎn)壓力蛋哭,在此簡(jiǎn)單解讀下县习,目的是能大概理解其原理。直接看導(dǎo)出的 API:createStore
谆趾、combineReducers
躁愿、bindActionCreators
、applyMiddleware
沪蓬、compose
彤钟,其中 bindActionCreators
暫時(shí)不想理會(huì),余下的依次介紹怜跑。
createStore
關(guān)鍵代碼(省去一些加強(qiáng)健壯性的代碼)以及對(duì)應(yīng)的解讀注釋如下:
// 函數(shù)接受三個(gè)參數(shù)样勃,第一個(gè)是 reducer吠勘,第二個(gè)是初始 state,第三個(gè)是由 applyMiddleware
// 生成的 enhancer
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.')
}
return enhancer(createStore)(reducer, preloadedState) // 可以看出 enhancer
// 是一個(gè)以 createStore 為參數(shù)然后返回一個(gè) createStore 的高階函數(shù)峡眶,待會(huì)兒通過(guò)
// applyMiddleware 可以看到這個(gè) enhancer 到底是怎么起作用的
}
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
function getState() { // 返回當(dāng)前的 state
if (isDispatching) {
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}
return currentState
}
function subscribe(listener) { // 訂閱函數(shù)剧防,每當(dāng) dispatch 的時(shí)候 listeners 都會(huì)執(zhí)行
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. ' +
'If you would like to be notified after the store has been updated, subscribe from a ' +
'component and invoke store.getState() in the callback to access the latest state. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
// 返回值是一個(gè)可以取消當(dāng)前 listener 訂閱的函數(shù)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. ' +
'See https://redux.js.org/api-reference/store#subscribe(listener) for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
// dispatch,通過(guò)這個(gè)函數(shù) dispatch action 借由 reducers 來(lái)生成一個(gè)新的 state
function dispatch(action) {
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?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) { // 如前所述辫樱,每 dispatch 一個(gè) action 時(shí)
// 都會(huì)去執(zhí)行所有的 listeners
const listener = listeners[i]
listener()
}
return action // 返回值和傳入的參數(shù)一樣峭拘,action
}
function replaceReducer(nextReducer) { // 替換 reducer
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
// replace reducer 后 dispatch 一個(gè) REPLACE action
dispatch({ type: ActionTypes.REPLACE })
}
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
// store 生成后 dispatch 一個(gè) INIT 的 action
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer
}
}
createStore
主要的作用就是根據(jù)提供的 reducer
、initialState
和 enhancer
生成 store
狮暑,然后 store 可以提供 dispatch
鸡挠、subscribe
、getState
搬男、replaceReducer
等方法拣展。
combineReducers
combineReducer
的作用是將多個(gè)(如果有的話) reducer
整合成一個(gè)總的 reducer
,關(guān)鍵代碼:
// reducers 是一個(gè) plain object缔逛,一個(gè) key 對(duì)應(yīng)一個(gè) reducer
export default function combineReducers(reducers) {
const reducerKeys = Object.keys(reducers)
const finalReducers = {}
for (let i = 0; i < reducerKeys.length; i++) {
const key = reducerKeys[i]
// 過(guò)濾無(wú)效的 reducer
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
const finalReducerKeys = Object.keys(finalReducers)
// 返回值依然是一個(gè)以 state 和 action 為參數(shù)的 reducer备埃,但是它可以處理所有的 type 的 action
return function combination(state = {}, action) {
let hasChanged = false
const nextState = {}
// 具體處理 action 的做法是,把每個(gè) action 代入所有 reducer 生成對(duì)應(yīng)的結(jié)果褐奴,然后再整合
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i]
const reducer = finalReducers[key]
const previousStateForKey = state[key]
const nextStateForKey = reducer(previousStateForKey, action)
nextState[key] = nextStateForKey
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
compose
這個(gè)方法的代碼最少:
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)))
}
funcs
是一個(gè)函數(shù)數(shù)組按脚,reduce
是數(shù)組的歸并方法。這個(gè)方法接受一系列的函數(shù)作為參數(shù)敦冬,而且這一系列函數(shù)辅搬,從右到左,上一個(gè)函數(shù)的返回值可以為下一個(gè)函數(shù)的參數(shù)脖旱,最終返回一個(gè)以最右邊的函數(shù)的參數(shù)為參數(shù)(這個(gè)參數(shù)再依次交給左邊的函數(shù)處理堪遂,返回后繼續(xù)此步驟,一直到最左邊)以最左邊的函數(shù)的返回值為返回值的復(fù)合函數(shù)萌庆。比如:
const F = compose(f1, f2. f3, f4, ..., fn)
F //f1(f2...(fn(...args)))
applyMiddleware
applyMiddleware
蚤氏,可以說(shuō)這個(gè)方法為 Redux 提供了各種可能性,關(guān)鍵代碼:
import compose from './compose'
export default function applyMiddleware(...middlewares) {
// 返回值是一個(gè)同時(shí)以 createStore 為參數(shù)和返回值的閉包
return createStore => (...args) => {
const store = createStore(...args) // 這里的store與沒(méi)有enhancer時(shí)的并無(wú)二致
let dispatch = () => {
throw new Error( // 中間件中不允許 dispatch
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
// 中間件API踊兜,規(guī)定了 middleware 是一個(gè)以 { getState, dispatch } 為參數(shù)的函數(shù)
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
// chain 的每個(gè)元素依然是一個(gè)函數(shù)竿滨,經(jīng)過(guò) compose 作用后返回一個(gè)合成函數(shù),合成函數(shù)以
// store.dispatch 為參數(shù),最終生成一個(gè)加強(qiáng)了的 dispatch
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
// 上面語(yǔ)句分開(kāi)寫就是 const composedFn = compose(...chain)
// dispatch = composedFn(store.dispatch)
// 其中 composedFn: (...args) => chain[0](chain[1](...(chain[length - 1](...args))))
// 可以看到捏境,`createStore` 經(jīng)過(guò) `storeEnhancer` 加強(qiáng)之后于游,其實(shí)只是用新的`dispatch` 將原來(lái)
// 的 `dispatch` 替換,其他的部分保持不變
return {
...store,
dispatch
}
}
}
這個(gè)方法接受一系列的 Redux 的 middleware
為參數(shù)垫言,然后返回一個(gè)以 createStore
為參數(shù)的 storeEnhancer
贰剥,其實(shí) storeEnhancer
enhance 的是 dispatch
(這里好像并不準(zhǔn)確,因?yàn)槌擞芍虚g件生成的 storeEnhancer 以外筷频,還有其他的 storeEnhancer蚌成,而這些 storeEnhancer 就有更強(qiáng)的功能前痘,比如像 devToolsExtension
這樣的擴(kuò)展工具)。由于每個(gè) middleware 在作用 { getState, dispatch }
后可以被 compose
處理担忧,那我們可以知道 middleware({ getState, dispatch })
的返回值是一個(gè)函數(shù)芹缔,而且這個(gè)函數(shù)的參數(shù)和返回值是具有相同簽名的函數(shù),于是 middleware 的函數(shù)簽名大概是:({ getState, dispatch }) => next => action
瓶盛,其中 next(action)
表示將 action
交由下一個(gè) middleware 處理最欠,最后一個(gè) middleware 的 next
即 dispatch
。
舉個(gè)例子:
//m1, m2, m3 是三個(gè)中間件
const middlewares = [m1, m2, m3]
const storeEnhancer = applyMiddleWare(...middlewares)
const store = createStore(reducer, {}, storeEnhancer)
export default store
store.dispatch
被強(qiáng)化的過(guò)程是這樣:
普通 dispatch
-> 被 m3
強(qiáng)化后的 dispatch
(記為 m3(dispatch)
) -> 再被 m2
強(qiáng)化后的 dispatch
(記為 m2(m3(dispatch))
) -> 再被 m1
強(qiáng)化后的 dispatch
(記為 m1(m2(m3(dispatch)))
惩猫。
對(duì)應(yīng)地芝硬,加載了上述中間件的 store
dispatch
一個(gè) action
的過(guò)程是這樣:
m1(m2(m3(dispatch)))(action)
-> next(action)
(next === m2(m3(dispatch))
)-> next(action)
(next === m3(dispacth)
)-> next(action)
(next === dispatch
)。