LoginSignup
1
1

More than 5 years have passed since last update.

redux-saga without redux reconnecting to redux

Last updated at Posted at 2019-04-07

やりたいこと

reduxに依存せずredux-sagaを使う
さらにその上で、
pureなreduxを使う

こちらの記事と方向性は似ていますがredux-sagaまでは捨てられません。
ReduxでのMiddleware不要論

なにがうれしいか

  • pureなreduxが使える。reduxはstoreを管理するだけになりシンプル
  • reduxに代わるステート管理の機構やフレームワークへの差し替えがきく

どうやるか

redux-sagaにはExternal APIとして、runSaga(options, saga, ...args)というredux-saga以外のコンテキストからsagaを実行するAPIが存在することは以外と知られていないかもしれません。以下を参照
https://redux-saga.js.org/docs/api/
これを使えば、redux middlewareにredux-sagaをインストールすることなく任意のsagaを実行できます。
まずは、以下のようなrunSaga()のラッパーを書きます。

helper.js
const sagaOptionSingleton = (() => {                                                                                              

    let channelStd = stdChannel();
    let emitter = new EventEmitter();

    emitter.on("action",channelStd.put);

    return {
        channel:channelStd,
        dispatch:output => {
            emitter.emit("action",output);
        },
        getState:() => {}
    };
 })();

export function runSagaWithFixedOpt(saga){                                                                                                            
  runSaga(sagaOptionSingleton,saga);
}

オプションにstdChannelのインスタンスを設定しているところが重要です。
公式ドキュメントではあまり説明されていませんが、
stdChannelはsagaのコンテキストで何らかのデータがyield putされた時sagaのaction channelにバッファするためのインターフェースです。これはシングルトンでなければいけません。
そのため、self executing functionでsagaOptionSingletonを生成し、runSagaのオプションは常にこれを使います。

このように、reduxのミドルウェアではなくなるため、当然ながらこのラッパーを使って実行するsagaやそこからフォークされるsagaの内部でyield putをしても、reduxのstoreには影響が及びません。
storeにデータを書き込みたければ普通にstore.dispatch()を使うだけです。
これでpureなreduxを使うことができるようになりました。

では、react-reduxのmapDispatchToPropsからdispatchされたアクションをsagaはどのように検知するか。

上記と同じ理由で検知できないので、
代わりに上記で書いたヘルパーを更にラップします。

helper.js
export function sendToSaga(data){
    function* sendSomethingToSaga(){    
       yield put(data);
    }
    runSagaWithFixedOpt(sendSomethingToSaga);
}

つまり非sagaコンテキストから単発のsagaを起動し、putを実行することでsagaへイベントを送ります。
すると、mapDispatchToPropsの実装は以下のようになります。

const mapDispatchToProps = dispatch => {
  return {
    increment: () => {
      sendToSaga({ type: 'INCREMENT' });//sagaへイベントを送る
    }
  }
}

このようにdispatchを使わなくなりました。(別に使っても良い)

結論

reduxに依存することなくredux-sagaを使うことができるようになりました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1