初学者のためのredux-observable・Epic入門

JavaScript

Observableについて

ObaservableはRxJSにおけるストリームを表現するクラスです。
RxJSではObservableを操作することでリアクティブプログラミングを実現します。

リアクティブプログラミングとは時間経過によって変化するデータを観測し、変更が生じた際にあらかじめ宣言した操作するというプログラミングのパラダイムです。
ストリームとは時間の経過によって変化するデータのことを指します。また、ストリームに存在する値のことをメッセージと呼びます。

Observableに関係する用語や概念の詳細解説は【RxJS入門】Observable、Observer、subscribe、Operatorの概要・関係性で紹介しています。

redux-observableについて

redux-observableはReduxでObservableを扱えるようにするミドルウェアです。

Epicについて

redux-observableではEpicと呼ばれる概念が登場します。
EpicはActionを受け取り、新たなActionを返す関数のことをいいます。公式ドキュメントでは、EpicはActionを受け取り新たなActionを返すため『アクションイン・アクションアウト』と表現されています。
Epicはアクションを常に監視し、Actionが実行(Dispatch)されたタイミングで処理を行います。

Epic内でActionはObservable(ストリーム)のデータ(メッセージ)として扱われます。つまり、Epicを型で表現すると以下のようになります。1
なお、Epicにおけるドルマーク($)はObservable変数を識別するためのRxJSの一般的な慣習です。

// Epicはアクションのストリームを受け取り、新たなアクションのストリームを返す
function (action$: Observable<Action>, state$: StateObservable<State>): Observable<Action>;

Epicから出力されたActionは即座に実行されます。コードで表現すると以下のようになります。1

// epic(action$, state$)の結果はObservable
// subscribeはObservableのメッセージ(ここでいうアクション)を取得するObservableのメソッド
// subcribeの第一引数はObservableのメッセージを処理する関数(Observer.next)

epic(action$, state$).subscribe(store.dispatch)

ReduxではActionの発行とReducerの実行は同期されているため、ActionとReducerの間には非同期処理を実装できません。
しかし、Epicを利用することで『Action in → 非同期処理 → Action out → Reducer』という処理の流れを実現できるため、ActionとReducerの間に非同期処理を実装できます。

Epicによる非同期処理の具体例

以下のコードはPINGというAction Typeが発行されてから1,000ms後にPONGというAction Typeを発行する例です。PINGの発行とPONGに対応するReducerの実行が非同期となります。1

const pingEpic = action$ => action$.pipe(
  ofType('PING'),
  delay(1000),
  mapTo({ type: 'PONG' })
);

以下のコードはTodo一覧をAPI経由で取得し、Stateにセットする例です。

const getTodosEpic: Epic<GetTodosActions | TodoActions> = (action$) =>
  action$.pipe(
    ofType(GetTodosType.GET_TODOS_REQUEST), // GET_TODOS_REQUESTというAction Typeが発行されたら以下を実行
    mergeMap(() => // メッセージを受け取り、新たなストリーム(Observable)を作成する
      from(axios.get("http://localhost:4000/todos")) // PromiseオブジェクトからObservableを生成
        .pipe(
          map((response) => setTodos(response.data)) // APIの結果をsetTodosを利用してStateにセットする
        )
    )
  );

なお、redux-observableを利用したTodoアプリケーションの具体的な実装の手順についてはTodoアプリで理解するredux-observableによる非同期処理の実装方法で紹介しています。

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

参考