redux-sagaからredux-observableに書き換えてみる

redux-sagaからredux-observableへ書き換え

仕事でredux-observableを使うことになったので、書き換えてみた備忘録。 ちなみにまだredux-observable触って2日目の初心者なので多目にみてもらえると :bow:

Before

よくあるredux-sagaの処理。 reducerstoreの設定周りとか、詳細は省きます。

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 => {
      return Rx.Observable.of(
        Rx.Observable.of(showLoading()),
        Rx.Observable.fromPromise(api.user.find(payload))
          .map(({ data }) => {
            return findUserSuccess(data);
          })
          .catch((error) => {
            return Rx.Observable.throw(error);
          }),
        Rx.Observable.of(hideLoading()),
      );
    })
    .concatMap((action) => {
      return Rx.Observable.zip(action, (data) => {
        return data;
      });
    })
    .catch((error) => {
      return Rx.Observable.of(findUserFail(error), hideLoading());
    })
}
  1. mappayloadを取得。
  2. mergeMapで非同期に処理を行う(Rx.Observable.ofで3つのObservableを返す)
  3. concatMapに3回Observableが渡されるので、ひとつずつ順番に処理する。

よく考えたらshowLoadingの前にapi.user.find(payload)が実行されちゃうから変な気がしてきた...うーむ orz

参考

Redux-Saga V.S. Redux-Observable Process Manager dispatch multiple actions #62

おしまい。

devalon

Read more posts by this author.