Reduxへの理解を深めるために、コードをいじってみて、どれぐらい大変か確認してみた。
実験的なものなので、プロダクションでは使わないように
発想
主にここ
https://gist.github.com/mizchi/d4a8455ef56a7adc123a388b3a5eaaaf
redux の reducer は非同期も取りたい。具体的には f(state: State, action: Action): State
ではなく f(state: State, action: Action): State | Promise<T>
としたい
できたもの
reducer が async/await で(Promiseで)書ける。
export default async (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'INCREMENT_ASYNC':
await new Promise(done => {
setTimeout(done, 500)
})
return await Promise.resolve(state + 1)
case 'DECREMENT':
return state - 1
default:
return state
}
}
実際の挙動。
感想
実際に作ってみると、ひたすら async await キーワードが伝搬していく感じだった
互換のものを作ろうとすると、どこまで仕様で、どこから仕様じゃないか理解してないと、この先書ける気がしなかった。似て非なるものを作るのは簡単。middleware を非互換に、subscribe を書き直すといい。
⋊> ~/p/redux on master yarn test
PASS test/typescript.spec.js
PASS test/createStore.spec.js
PASS test/combineReducers.spec.js
PASS test/applyMiddleware.spec.js
PASS test/bindActionCreators.spec.js
PASS test/compose.spec.js
PASS test/utils/warning.spec.js
Test Suites: 7 passed, 7 total
Tests: 16 skipped, 51 passed, 67 total
Snapshots: 0 total
Time: 5.181s
Ran all test suites.
非同期APIを取ることでそもそもテスト側を障る必要もあり、互換というわけではない。
全然関係ないが、 jest のアサーションが非同期に対して貧弱すぎてクソという感想をもった。
できなかったこと
- オリジナルの Middleware と互換にしたかったが、実行順の関係で、非同期用に書き直さないといけないとたぶんダメ。src/compose.js を読み切ればなんかできるかも。
- subscribe されたものが発火する順番が、オリジナルと変わってしまっている。
そもそも middleware 使わなくていいように reducer で非同期取れるようにしてるんだから、Middlewareは redux-logger が動くぐらいでいいのかもしれない。subscribe はなんとかしたい。
この辺で時間切れ