redux
是什麼、有什麼作用,解決什麼問題,如果你還不知道,請先去這裡: redux中文文件
下面的文章適合對redux有一定理解和使用經驗的人
專案github地址:github.com/wangweiange…
如果你覺得對你有幫助的話記得給我一個star呢
applyMiddleware有什麼用:
使用包含自定義功能的 middleware 來擴充套件 Redux 是一種推薦的方式。
Middleware 可以讓你
同時, middleware 還擁有“可組合”這一關鍵特性。多個 middleware 可以被組合到一起使用,形成 middleware 鏈。
其中標紅色的部分是我們很常用到的,例如redux-thunk
、redux-promise
外掛。
若要很好的理解applyMiddleware
我們納入redux-thunk
原始碼來分析:
先看看 applyMiddleware的原始碼:
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}複製程式碼
非常的簡潔,整體含義就是:applyMiddleware 接收多個引數,並返回一個以createStore為引數的function,此function經過一系列的處理之後返回了 createStore裡面的所有方法和重寫的dispatch。
這裡還是不能很好理解的話我們來看看redux-thunk
的原始碼:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;複製程式碼
也是非常的簡潔接收一個extraArgument引數,返回一個{ dispatch, getState }為引數的function,即最終返回的是這個函式:
從原始碼中可以看出 thunk 最終的值為 這個function
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};複製程式碼
讓我們來簡化一下它用通俗的方式改寫如下,
//用通俗的程式碼重寫
let AAA = function (opt) {
var dispatch = opt.dispatch,
getState = opt.getState;
return function (next) {
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
};
};複製程式碼
可以很清晰的看出,傳入了dispatch和getState,返回了一個函式,並判斷函式的action引數是否為function做不同的處理,其中標識為紅色的為實現非同步的核心。
也許還是不能理解所以然,下面讓我們來理清它。
來看看createStore,applyMiddleware 加上 redux-thunk 之後的呼叫方式:
import thunk from 'redux-thunk'
import { createStore,applyMiddleware } from './redux'
const store = createStore(
reducers,
applyMiddleware(thunk)
)複製程式碼
我們來給一個reducers測試案例來分析原始碼的走向,完整程式碼如下:
import thunk from 'redux-thunk'
import { createStore,applyMiddleware } from './redux'
const ADD_TODO = 'ADD_TODO'
function reducers(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([ action.text ])
default:
return state
}
}
// 建立 Redux 的 store 物件
const store = createStore(
reducers,
applyMiddleware(thunk)
)
console.log(store.getState())複製程式碼
下面我通過在程式碼中註釋的方式來說明執行流程:
//此時 ...middlewares = [ AAA ] AAA在上面有說明
export default function applyMiddleware(...middlewares) {
//返回一個函式 唯一的引數為 createStore,也就是redux中的createStore函式
return (createStore) => (reducer, preloadedState, enhancer) => {
//這裡相執行了createStore方法 傳了3個引數,
//這三個引數從createStore.js 中的 return enhancer(createStore)(reducer, preloadedState) 得來,可以看出傳來的引數只有2個
//因此也就不會再執行createStore.js中的 enhancer函式
const store = createStore(reducer, preloadedState, enhancer)
//這裡得到了store,拿取createStore.js 中的dispatch函式 儲存在dispatch臨時變數中
let dispatch = store.dispatch
//因為 ...middlewares 是一個陣列,臨時儲存
let chain = []
//包裝 getState 和 dispatch 兩個方法
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
/*
迴圈呼叫
體現在案例中時 middlewares 的值為 [AAA] 因此執行一次
返回的chain為 [ AAA(middlewareAPI) ], 可以看出middlewareAPI值正是AAA函式需要的兩個引數
體現在案例中此時 chain 值為:
[
function (next) {
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
},
]
*/
chain = middlewares.map(middleware => middleware(middlewareAPI))
/*
這段程式碼執行完之後會得到新的dispatch
體現在案例中下面這段程式碼返回值dispatch為:
function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return store.dispatch(action);
};
這裡的面的 next 值為 store.dispatch
*/
dispatch = compose(...chain)(store.dispatch)
//最終返回新的createStore方法,重寫了dispatch,其他的都沒有變
return {
...store,
dispatch
}
}
}複製程式碼
根據以上的分析我們來給一個非同步的actions案例,並dispatch呼叫:
function actions(){
return (dispatch)=>{
dispatch({
type: ADD_TODO,
text: 'Read the docs'
})
}
}
//使用redux-think處理之後的dispatch觸發actions
store.dispatch(actions())複製程式碼
根據以上的分析我們知道最終處理之後返回的dispatch
值為:
function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return store.dispatch(action);
};複製程式碼
當呼叫actions()之後我們可以明顯的看出 typeof action === 'function' 為真
因此走是return action(dispatch, getState, extraArgument);
,再去觸發reducers函式
最終通過 currentState = currentReducer(currentState, action)
從而改變唯一的store狀態資料
經過以上的分析就能很好的理解alpplyMiddleware
這個方法和redux-thunk
的主要作用了。
接下來我們進入到redux的最後一個方法 bindActionCreators
redux v3.7.2原始碼解讀與學習之 bindActionCreators
關注我的部落格:zane的個人部落格
原文地址:redux v3.7.2原始碼解讀與學習之 applyMiddleware