redux 的中介軟體提供的是位於action
被發起之後,到達reducer
之前的擴充套件點,換而言之,原本view -> action -> reducer -> store
的資料流加上中介軟體後變成了view -> action -> middleware -> reducer -> store
,在這一環節我們可以做一些 「***」 的操作,如 非同步請求、列印日誌等。
以日誌輸出 logger 為例:
'redux'
/** 定義初始 state**/
const initstate =
/** 定義 reducer**/
const reducer = (state, action) =>
default:
break
}}/** 定義中介軟體 **/
const logger = () => next => action =>
/** 建立 store**/
/** 現在嘗試傳送乙個 action**/
store.dispatch()
/** 列印:**/
// 【logger】即將執行:
// 【logger】執行完成後 state:
複製**
要理解上面這段**,首先要從建立store
的createstore
函式說起:
createstore
函式接收引數為(reducer, [preloadedstate], enhancer)
,其中preloadedstate
為初始state
,那麼enhancer
又是什麼呢?從官方文件可以看到,storecreator
的函式簽名為
type storecreator = (reducer: reducer, initialstate: ?state) => store複製**
是乙個普通的建立store
的函式,而enhancer
的簽名為
type enhancer = (next: storecreator) => storecreator複製**
可知enhancer
是乙個組合storecreator
的高階函式
, 返回的是乙個新的強化過的storecreator
,再執行storecreator
就能得到乙個加強版的store。
export
default
function
return
(createstore) => (reducer, preloadedstate, enhancer) =>
// 註冊中介軟體呼叫鏈,並由此可知,所有的中介軟體最外層函式接收的引數都是
chain = middlewares.map(middleware => middleware(middlewareapi))
//compose 函式起到**組合的作用:compose(f, g, h)(...args) 效果等同於 f(g(h(...args))),具體實現可參見附錄。從此也可見:所有的中介軟體最二層函式接收的引數為 dispatch,一般我們在定義中介軟體時這個形參不叫 dispatch 而叫 next,是由於此時的 dispatch 不一定是原始 store.dispatch,有可能是被包裝過的新的 dispatch。
dispatch = compose(...chain)(store.dispatch)
// 返回經 middlewares 增強後的 createstore
return
}}複製**
這樣下來,原來執行dispatch(action)
的地方變成了執行新函式
(action)=>複製**
這樣就實現了action -> reducer
的攔截,所以每次觸發action
都能被 log 出來了,?。
對於非同步中介軟體的情況也同理 , 以redux-thunk
為例:
// 這是簡化後的 redux-thunk
const thunk = () => next => action =>
return next(action);
};複製**
這裡可以看到,當dispatch
的收到的action
為函式時,將試圖巢狀執行這個函式。套用這個中介軟體後的dispatch
方法就更 「聰明」 了,這就是為什麼redux
中規定action
必須為純物件而在redux-thunk
中傳的action
卻是function
而不會報錯的原因。
redux 中介軟體通過改寫 store.dispatch 方法實現了action -> reducer
的攔截,從上面的描述中可以更加清晰地理解 redux 中介軟體的洋蔥圈模型
:
中介軟體a -> 中介軟體b-> 中介軟體c-> 原始 dispatch -> 中介軟體c -> 中介軟體b -> 中介軟體a複製**
這也就提醒我們使用中介軟體時需要注意這個中介軟體是在什麼時候 「搞事情」 的,比如redux-thunk
在執行next(action)
前就攔截了型別為function
的action
,而redux-saga
就在next(action)
才會觸發監聽sagaemitter.emit(action)
, 並不會攔截已有action
到達reducer。
export
default
function
compose(...funcs)
if (funcs.length === 1)
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return
(...args) => rest.reduceright((composed, f) => f(composed), last(...args))
}複製**
精妙之處就在巧妙的利用了array.prototype.reduceright(callback[, initialvalue])
這個我們平時不怎麼用到的函式。該方法將陣列中每一項從右向左呼叫callback
,本例中的callback
即為
(composed, f) => f(composed)複製**
initialvalue
初始值是陣列中最後乙個func。
這裡下面是另一種實現:
const compose = (...funcs) => (result) =>
return result;
}複製**
這種寫法就更容易理解為什麼compose(f, g, h)(...args)
效果等同於f(g(h(...args)))
,但是就沒有上面那種優雅?。 解讀 Redux 中介軟體的原理
redux 的中介軟體提供的是位於action被發起之後,到達reducer之前的擴充套件點,換而言之,原本view action reducer store的資料流加上中介軟體後變成了view action middleware reducer store,在這一環節我們可以做一些 的操作,如 非...
redux中介軟體原理
應用了如下的中介軟體 a,b,c 整個執行 action 的過程為 a b c dispatch c b a action 最右側的next action 返回的是應用傳入的action 該行為是由redux createstore原始碼中dispatch方法返回值決定的,不過一般都會return ...
Redux中介軟體的原理
中介軟體顧名思義就是誰和誰的中間,在圖中 view在redux會派發乙個action,action通過store的dispatch方法派發給store,store接收到action 連同之前state 一同傳給reducer reducer會返回乙個新的資料給store store然後去改變自己的s...