redux-sagaからredux-observableへ書き換え
仕事でredux-observableを使うことになったので、書き換えてみた備忘録。
ちなみにまだredux-observable触って2日目の初心者なので多目にみてもらえると ![]()
Before
よくあるredux-sagaの処理。
reducerとstoreの設定周りとか、詳細は省きます。
import { createAction } from 'redux-actions';
export const findUser = createAction('findUser');
function * findUserHandler(payload) {
try {
yield put(showLoading());
const { data } = yield call(api.user.find, payload);
yield put(findUserSuccess(data));
} catch (error) {
yield put(findUserFail(error.response));
} finally {
yield put(hideLoading());
}
}
export default function * rootSaga() {
yield [
takeEvery(actions.findUser.toString(), findUserHandler)
]
);
厄介なのはshowLoadingアクションとhideLoadingアクションを非同期処理の処理の前後で呼ぶところです。
issueでもこんな質問が上がってましたが、そもそも解決策が高度過ぎて理解ができなくて解決できず・・・orz
ここに書いてあるような感じだとパラメータ固定で実用的でないし、、、。
ので、自分で書いてみることにしました。
After
試行錯誤の結果、ソースコードがこうなりました。
export default function findUser(action$) {
return action$.ofType(actions.findUser.toString())
.map(action => action.payload)
.mergeMap(payload => Rx.Observable.of(
Rx.Observable.of(showLoading()),
Rx.Observable.fromPromise(api.user.find(payload))
.map(({ data }) => findUserSuccess(data))
.catch((error) => Rx.Observable.throw(error)),
Rx.Observable.of(hideLoading()),
)
)
.concatMap((action) => Rx.Observable.zip(action, (data) => data))
.catch((error) => Rx.Observable.of(findUserFail(error), hideLoading()))
}
-
mapでpayloadを取得。 -
mergeMapで非同期に処理を行う(Rx.Observable.ofで3つのObservableを返す) -
concatMapに3回Observableが渡されるので、ひとつずつ順番に処理する。
よく考えたらshowLoadingの前にapi.user.find(payload)が実行されちゃうから変な気がしてきた...
でもPromiseObservableで待ってくれてるぽい。。。うーむ orz
参考
Redux-Saga V.S. Redux-Observable
Process Manager dispatch multiple actions #62
おしまい。