三個概念:(state, action) => stateredux
{type: 'COMPLETE_TODO',index: 1}
首先咱們先看下 createStore 的參數列表及其返回值:app
export default function createStore(reducer, preloadedState, enhancer) { // 第一個參數reducer(function類型),preloadedState是初始state,enhancer參見下面解釋 // 第二,第三參數可爲空,可互換,這裏不列源碼了 // ... // 返回一個包含一大堆函數的對象,具體做用咱們後面看,這裏咱們首先知道它是返回了一個對象 return { dispatch, subscribe, getState, replaceReducer, [$$observable]: observable } }
enhancers 英語譯爲「加強劑」,其實做用也的確如此。用一個表達式來解釋:函數
// f方法對 g 方法作了一些功能加強 h(x) = f(g(x));
例如:this
const g = (t)=>{ console.log(`do ${t} task`); } const f = (func) => { console.log('add enhancers'); return func; } const h = f(g); h('first');
其實 Store Enhancers 也就是這個概念,來看相關源碼:spa
export default function createStore(reducer, preloadedState, enhancer) { // ... if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) } // ... }
從源碼中能夠看出兩點:日誌
createStore
函數傳給咱們寫的 enhancerreducer
,preloadedState
參數也會傳給咱們不知道這樣是否是很清晰了?咱們來寫一個例子,功能相似簡化版的 redux-logger,能夠在每一個dispatch
時打印日誌。code
function createLogger(createStore){ return (reducers,initialState) => { const store = createStore(reducers, initialState); function dispatch(action){ console.log(`dispatch an action: ${JSON.stringify(action)}`); const res = store.dispatch(action); const newState = store.getState(); console.log(`current state: ${JSON.stringify(newState)}`); return res; } return {...store,dispatch}; } } var store = Redux.createStore(counter,createLogger);
這樣就實現了一個記錄日誌的功能,每次 dispatch
的時候都會記錄。
有些人可能想到了,enhancer權力好像有些大?是的,它能夠加強 store 的行爲,同時也可能破壞它,因此你們寫 enhancers 的時候必定要注意:__不要破壞了Redux的原有工做流__。好比上面例子中這行代碼就保證了 Redux 本來的工做流。對象
const res = store.dispatch(action);
可能會有人還不知道 Middleware 的含義,仍是來解釋一下吧,說洋蔥模型可能太文藝了,舉這麼個例子吧,超級瑪麗爲了救公主要經歷 1-1,1-2,1-3,1-4...8-4 關,才能救到公主,這裏的每一關就能夠理解成一個Middleware,只不過如今咱們是遊戲製做人,關卡由咱們來設定。遊戲
若是你看了上面的實例,可能會想 redux-logger 不是一個 Middleware 嗎?和 store enhancers 是什麼關係啊?咱們先來看一下在 redux 中如何定義一個 Middleware,舉官網上的例子:文檔
import { createStore, combineReducers, applyMiddleware } from 'redux' let todoApp = combineReducers(reducers) let store = createStore( todoApp, applyMiddleware(logger, crashReporter) )
你們再回想上面例子的代碼:
var store = Redux.createStore(counter,createLogger);
是否是很類似呢?沒錯,原理都是一個。這裏調用了 Redux 提供的 applyMiddleware 方法,從而實現了咱們上面的過程。因此,我把這裏的 Middleware 概括成 __一個只能夠擴展 dispatch 方法的 Store Enhancers__。下面列出 applyMiddleware 方法的源碼吧,很簡單相信你們均可以看懂。
export default function applyMiddleware(...middlewares) { return createStore => (...args) => { const store = createStore(...args) let dispatch = () => { throw new Error( `Dispatching while constructing your middleware is not allowed. ` + `Other middleware would not be applied to this dispatch.` ) } let chain = [] const middlewareAPI = { getState: store.getState, dispatch: (...args) => dispatch(...args) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
顧名思義,reducer的「加強劑」。首先咱們再回到 createStore 中,第一個參數咱們須要定義reducers,不考慮state分割的狀況下,咱們可能會定義成這樣:
function counter(state, action) { if (typeof state === 'undefined') { return 0 } switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state } }
然而這個「模板」是一直從 Redux 文檔中流傳下來的,但若是我寫成這樣呢?
function counter(state,action){ //我啥也不作 }
實時證實在寫成這樣在 createStore 的時候也能夠經過的,只不過在store.getState()
的時候是undefined
。
因此,我的認爲沒有什麼 reducer enhancers
的概念。
其實很簡單,直接看源碼:
function dispatch(action) { // 各類判斷 try { isDispatching = true // 正常狀況下 currentReducer 就是咱們傳進去的 reducer currentState = currentReducer(currentState, action) } finally { isDispatching = false } const listeners = (currentListeners = nextListeners) for (let i = 0; i < listeners.length; i++) { const listener = listeners[i] listener() } return action }
上述代碼中,咱們還看到 dispatch 的時候還會調用 listener()
,listeners
是經過 subscribe
方法來訂閱的,好比一般咱們所作的會把 render
方法添加到這裏。這樣就能夠實現數據變化後從新渲染了。