Middleware 稱為中介層,在許多後端伺服器框架中都可以看到 Middleware 的應用,Middleware 會在定義好的起點與終點之間,針對中間的過程做處理。
Redux Middleware 則是在 Action 進入到 Reducer 之前,可以讓我們做一些介入 Action 的時間點,它在 dispatch action 和 action 到達 reducer 的時間點之間提供了一個第三方的擴充點。
在 React 中,可以擁有很多個 Middleware,每個 Middleware 會檢查自己份內要處理的 Action,無論有沒有處理都會傳給下一個串連的 Middleware 做處理。
透過 Redux Middleware,可以對 Action 做延遲、記錄、調整或停止的處理,實務上可用以做 Log 回報、執行非同步 API、Routing 等功能處理。
把一個或多個 Middleware 傳入 Redux 提供的 applyMiddleware 函式,再把 applyMiddleware 函式,傳入 createStore 的第二個參數即可。
import { createSotre, applyMiddleware} from 'redux';
const store = createStore(
reducers,
applyMiddleware(
middlewareOne,
middlewareTwo
)
);
為了讓程式碼更好理解且增加彈性,也可用一個變數 enhancers 做為 applyMiddleware 函式的回傳。
import { createSotre, applyMiddleware} from 'redux';
const enhancers = applyMiddleware(middlewareOne, middlewareTwo);
const store = createStore(reducers, enhancers);
Middleware 的樣版長的像這樣:
function middleware(store) {
return function(next) {
return function(action) {
/* Code */
return next(action);
};
};
}
使用 ES6 Arrow Function 簡化後的寫法
const middleware = store => next => action => {
/* Code */
return next(action);
};
next 是用來將 Action 交棒給下一個 Middleware 的處理的函式。
每一個 Middleware 接到的 Action 都會是前一個 Middleware 呼叫 next 傳入的 Action,如果沒有下一個 Middleware 就會交由 Reducer 處理。
接下來會使用 Log 及當機回報做為範例,來深入探究 Middleware 的形成思考過程。
先套用 boilerplate 如下
const logger = store => next => action => {
// do something
return next(action);
};
製作一個 Logger Middleware,用來打印出每個 dispatch 的 action 及 action 之後的 state,當發生不符合預期結果時,可以檢查 log 找出是哪一個 action 破壞了 state。
const logger = store => next => action => {
// 印出要做 dispatch 的 action
console.log('dispatching', action);
let result = next(action)
// 印出 action 處理完的 new state
console.log('next state', store.getState())
return result;
};
當在 dispatch 一個 action 時,如果發生失敗時,可以把錯誤堆疊、導致錯誤的 action 和當下的 state 傳送到一個當機回報服務(範例使用 Raven.captureException ),協助在開發環境中重現錯誤。
const crashReporter = store => next => action => {
try {
return next(action);
} catch (err) {
console.error('Caught an exception!', err);
/* 實務上可用的當機回報服務
Raven.captureException(err, {
extra: {
action,
state: store.getState()
}
});
*/
throw err;
}
};
import {
createSotre,
combineReducers,
applyMiddleware
} from 'redux';
const reducers = combineReducers(todosReducer, filterReducer);
const enhancers = applyMiddleware(logger, crashReporter);
const store = createStore(reducers, enhancers);
完整程式碼實作:https://codesandbox.io/s/react-todomvc-redux-middleware-tugoii
現在任何被 dispatch 到 store 的 action 都將經過 logger 和 crashReporter
理解完 React Middleware 的運作原理後,我們可以繼續來看看有哪些實務上大家都在使用 Redux Middleware,以及它們分別幫忙解決了什麼問題。
https://max80713.medium.com/%E8%A9%B3%E8%A7%A3-redux-middleware-efd6a506357e
https://pjchender.dev/react/redux-middleware/
https://chentsulin.github.io/redux/docs/advanced/Middleware.html