一、何であるか#
ミドルウェア(Middleware)は、アプリケーションシステムとシステムソフトウェアの間にあるソフトウェアの一種であり、システムソフトウェアが提供する基本サービス(機能)を使用して、ネットワーク上のアプリケーションシステムのさまざまな部分や異なるアプリケーションを接続し、リソース共有や機能共有を実現することができます。
前の記事では、Redux
のワークフロー全体を理解しました。action
が発行されると、reducer
がすぐにstate
を計算します。このプロセスは同期的な操作です。
したがって、非同期操作をサポートしたり、エラー処理やログ監視をサポートしたりする場合、ミドルウェアを使用することができます。
Redux
では、ミドルウェアはdispatch
プロセス中に配置され、action
のディスパッチをインターセプトして処理します。以下の図を参照してください:
ミドルウェアは本質的には関数であり、store.dispatch
メソッドを変更し、Action
の発行とReducer
の実行の間に他の機能を追加します。
二、よく使用されるミドルウェア#
優れたredux
ミドルウェアは多数あります。例えば:
- redux-thunk:非同期操作に使用されます
- redux-logger:ログの記録に使用されます
上記のミドルウェアはすべてapplyMiddlewares
を使用して登録する必要があります。これは、すべてのミドルウェアを配列にまとめて順番に実行するためのものです。
次に、createStore
に第 2 引数として渡すために、これを第 2 引数としてcreateStore
に渡します。
const store = createStore(
reducer,
applyMiddleware(thunk, logger)
);
redux-thunk#
redux-thunk
は公式サイトで推奨されている非同期処理のミドルウェアです。
デフォルトのdispatch(action)
では、action
は JavaScript のオブジェクトである必要があります。
redux-thunk
ミドルウェアは、渡されたデータの型をチェックし、関数である場合は(dispatch、getState)を関数に渡します。
- dispatch 関数は、後でアクションを再度ディスパッチするために使用されます
- getState 関数は、後の操作には元の状態に依存する必要があるため、以前の状態を取得できるようにします
したがって、dispatch
は次のような関数として書くことができます:
const getHomeMultidataAction = () => {
return (dispatch) => {
axios.get("http://xxx.xx.xx.xx/test").then(res => {
const data = res.data.data;
dispatch(changeBannersAction(data.banner.list));
dispatch(changeRecommendsAction(data.recommend.list));
})
}
}
redux-logger#
ログ機能を実装したい場合は、既存のredux-logger
を使用することができます。
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(
reducer,
applyMiddleware(logger)
);
これにより、ミドルウェア関数を使用して簡単にログを記録できます。
三、実装原理#
まず、applyMiddlewares
のソースコードを見てみましょう。
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer);
var dispatch = store.dispatch;
var chain = [];
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
};
chain = middlewares.map(middleware => middleware(middlewareAPI));
dispatch = compose(...chain)(store.dispatch);
return {...store, dispatch}
}
}
すべてのミドルウェアは配列chain
に入れられ、ネストされて実行され、最後にstore.dispatch
が実行されます。中間ウェア内部(middlewareAPI
)では、getState
とdispatch
の 2 つのメソッドにアクセスできます。
上記の学習で、redux-thunk
の基本的な使用方法を理解しました。
内部では、dispatch
が判断され、対応する操作が実行されます。原理は次のようになります:
function patchThunk(store) {
let next = store.dispatch;
function dispatchAndThunk(action) {
if (typeof action === "function") {
action(store.dispatch, store.getState);
} else {
next(action);
}
}
store.dispatch = dispatchAndThunk;
}
ログ出力を実現する原理も非常に簡単です。次のようになります:
let next = store.dispatch;
function dispatchAndLog(action) {
console.log("dispatching:", addAction(10));
next(addAction(5));
console.log("新しいstate:", store.getState());
}
store.dispatch = dispatchAndLog;