2016/07/14 に行われた M3 tech meetup! #2 で使った発表資料です。
redux-sagaで副作用をコントロールする@kuy / Yuki Kodama2016.07.14 @ M3 tech meetup! #2
View Slide
自己紹介@kuy (カイ) / Yuki Kodama株式会社ジャパンベンチャーリサーチentrepedia(アントレペディア)の開発・運用AWS, Ruby on Rails, JavaScript (React + Redux)● redux-sagaで非同期処理と戦う● Reduxでコンポーネントを再利用する● Reduxのmiddlewareを積極的に使っていく● ・・・などQiita の記事発表 ● なぜReduxを使うのか
副作用とは「状態を変更して、そのあとの計算に影響を与えること」● それ、全部じゃね・・・?● 副作用がないと現実世界に影響を与えられない
副作用の何が困るのか● 明示的に与えた入力以外のデータに依存している○ グローバル変数など● 計算結果以外に何か状態を変化させる○ 通信処理とかもこれに含まれる影響の範囲を予測しづらい
副作用をコントロールする● 副作用を発生させる場所を限定する● 副作用コードをテスト可能にする
Redux での副作用1. ユーザーによるイベントが発生2. アプリケーションの状態からパラメータを決定3. リクエストを発行4. 取得したデータを状態に反映典型的な副作用として通信処理を考える
redux-thunk による実装Action Creator
redux-thunk の問題点● 外からは何が行われるのかわからない○ dispatchやgetStateは使われているのか?○ 通信処理を開始するのか?● 本来Actionを生成するだけのはずのAction Creatorが関数を返す○ PromiseのCallback Hellを引き起こすredux-thunk は「GOTO文ミドルウェア」[Medium] “Redux side effects and you” by Francois Ward
redux-saga● Reduxミドルウェアの一種● 副作用のあるコードを一手に引き受ける● 非同期コードを同期的に書ける(coみたいなやつ)● テストしやすくなる
redux-saga の仕組みSagaと呼ばれる独立して動く処理を定義 Effectsを使ってロジックを記述● Generator関数(yieldを使う)● 小さなタスクのような感じ● call: (非)同期関数呼び出し● select: 状態の取得する● put: Actionのdispatch● take: Actionを待ち受ける● fork: 別の Saga を起動する● cancel: 起動した Saga を中止する● ....などなどredux-saga が提供する実行環境で Saga を起動する
redux-saga の動作イメージ
redux-saga による実装Action CreatorSelectorSaga
2つのコードの違い● redux-thunkは副作用コードを関数でラッピングしている● redux-sagaは副作用コードをデータとして扱って、実行はミドルウェアに任せている副作用をその場で実行しているかどうかテストのしやすさにつながる
副作用コードをデータとして扱うyield api('/hoge'); // BADyield call(api, '/hoge'); // GOODデータとして扱えていないケースデータとして扱えているケースPromise が yield される。解決を待ってくれるけど、どの関数を呼び出したのかが不明であるEffect オブジェクトが yield される。ただのオブジェクトなので何を呼び出したのかわかる
Saga のテストコードぎりぎりまでモックを使わないでテストできる
まとめ● 副作用はなくてはならないものなので、プログラム全体に散らばらないように書く場所を限定する● redux-saga は副作用コードをデータとして扱うためのライブラリ● テストしやすいコードにしておくのは大事
参考資料[Qiita] “AffですべてのPromises/Generatorsを過去にする/そして何故我々は作用をモナドで抽象化すべきなのか” by @hiruberuto[GitHub] “Redux Ecosystem Links > Side Effects”markerikson/redux-ecosystem-links
Thank you!