[前回] 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
は、パイプラインのnext
Middleware- 引数として
next
を受け取る -
next(action)
を呼び出すと、パイプライン内のnext
Middlewareに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を確認 - 最後に、
next
Middlewareから得られた結果値を返す
-
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/todoAdded
actionが発生したら- 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をカスタマイズしました。
次回も続きます。お楽しみに。