[前回] Django+Reactで学ぶプログラミング基礎(35): Reduxチュートリアル(TodoアプリのStoreをカスタマイズ)
はじめに
前回は、EnhancerとMiddlewareを用いてStoreをカスタマイズしました。
今回は、Middlewareの続きです。
今回の内容
- カスタムMiddlewareの作成
- Middlewareのユースケース
カスタムMiddlewareの作成
- 独自のMiddlewareを作成し、特定動作をReduxアプリに追加
- 下記Middlewareは、3つのネストされた関数として記述されている
- 一番外側の関数
exampleMiddlewareは、Middlewareそのもの-
applyMiddlewareにより呼び出され、storeAPIオブジェクトを引数として受け取る- storeの
{dispatch、getState}関数を含む
- storeの
- dispatch関数を呼び出すと、actionが送信され、Middlewareパイプラインが開始する
- これは一度だけ呼び出される
-
- 真ん中の関数
wrapDispatchは、パイプラインのnextMiddleware- 引数として
nextを受け取る -
next(action)を呼び出すと、パイプライン内のnextMiddlewareにactionが渡される- これも一度だけ呼び出される
- このMiddlewareがシーケンスの最後のMiddlewareの場合
-
nextはオリジナルのstore.dispatch関数となる
-
- 引数として
- 一番内側の関数
handleActionは、actionがdispatchされるたびに呼び出される- 引数として現在のactionを受け取る
- 一番外側の関数
// Middleware written as ES5 functions
// Outer function:
function exampleMiddleware(storeAPI) {
return function wrapDispatch(next) {
return function handleAction(action) {
// Do anything here: pass the action onwards with next(action),
// or restart the pipeline with storeAPI.dispatch(action)
// Can also use storeAPI.getState() here
return next(action)
}
}
}
- 上記Middlewareを、ES6のアロー関数を使用し、短く書ける
- アロー関数にreturnステートメントが必要ない
const anotherExampleMiddleware = storeAPI => next => action => {
// Do something in here, when each action is dispatched
return next(action)
}
カスタムMiddlewareの例1: 更新後のstateをコンソール出力する
- actionがdispatchされると、Middlewareパイプライの下記処理が走る
-
handleAction関数により、dispatchingメッセージがコンソール出力される - actionを
nextセクションに渡す-
nextセクションは、別のMiddleware、またはオリジナルのstore.dispatchとなる - 最終的に、reducerが実行され、stateが更新される
-
next関数が返される
-
-
storeAPI.getState()を呼び出し、新しいstateを確認 - 最後に、
nextMiddlewareから得られた結果値を返す
-
const loggerMiddleware = storeAPI => next => action => {
console.log('dispatching', action)
let result = next(action)
console.log('next state', storeAPI.getState())
return result
}
- すべてのMiddlewareは任意の値を返すことができる
-
store.dispatch()を呼び出すと、最終的返却されるのはパイプラインの最初Middlewareの戻り値- 以下の例で、返却されるのは
Hello!- オリジナル
store.dispatchの結果ではない
- オリジナル
- 以下の例で、返却されるのは
const alwaysReturnHelloMiddleware = storeAPI => next => action {
const originalResult = next(action);
// Ignore the original result, return something else
return 'Hello!'
}
const middlewareEnhancer = applyMiddleware(alwaysReturnHelloMiddleware)
const store = createStore(rootReducer, middlewareEnhancer)
const dispatchResult = store.dispatch({type: 'some/action'})
console.log(dispatchResult)
// log: 'Hello!'
カスタムMiddlewareの例2: 内部で非同期ロジックを実行
- Middlewareはdispatchされた特定actionのみ処理可能
- Middlewareは、内部で非同期ロジックを実行可能
- 以下の例で、
todos/todoAddedactionが発生したら- 1秒遅延後に
action.payloadをコンソール出力
- 1秒遅延後に
- 以下の例で、
const delayedMessageMiddleware = storeAPI => next => action => {
if (action.type === 'todos/todoAdded') {
setTimeout(() => {
console.log('Added a new todo: ', action.payload)
}, 1000)
}
return next(action)
}
Middlewareのユースケース
-
dispatchされたactionに対し、下記追加処理を実行
- コンソールにログ出力
- タイムアウトを設定
- 非同期API呼び出し
- acitonを変更
- actionを一時停止するか、完全停止
-
Middlewareに、副作用のあるロジックを含められる
- dispatchを変更し、プレーンでないオブジェクトをactionとして受け入れられる
- プレーンでないオブジェクトとは
- Class
- Promise
- function
- その他組み込みJSタイプ
- Map
- Set Promise
- Date
- プレーンでないオブジェクトとは
- dispatchを変更し、プレーンでないオブジェクトをactionとして受け入れられる
おわりに
Redux Middlewareを使用し、Storeをカスタマイズしました。
次回も続きます。お楽しみに。