redux-sagaでtakeEveryをcancelする

takeEveryで動かしている処理をcancelしたい場合、raceを使って停止させます。 これは、raceで何もしない処理と同時実行することで、「何もしない処理が先に完了したので、処理を完了とする」判定を出すやり方で […]

広告ここから
広告ここまで

目次

    takeEveryで動かしている処理をcancelしたい場合、raceを使って停止させます。

    /**
     * Actions
     **/
    const START = 'START' as const
    const CANCEL = 'CANCEL' as const
    const start = () => ({
     type: START,
    })
    const cancel = () => ({
     type: CANCEL
    })
    
    function* startSaga() {
      // Do something
    }
    
    function* exampleSaga() {
      yield takeEvery([START], function*(...args) {
        yield race({
          task: call(startSaga, ...args),
          cancel: take(CANCEL)
        })
      }
    }

    これは、raceで何もしない処理と同時実行することで、「何もしない処理が先に完了したので、処理を完了とする」判定を出すやり方で、Automatic cancellationとしてドキュメントにも紹介されています。

    In a race effect. All race competitors, except the winner, are automatically cancelled.

    https://redux-saga.js.org/docs/advanced/TaskCancellation/#automatic-cancellation

    ラッパー関数を作るなら

    頻繁にCancelの必要があるtakeEveryを書く場合は、以下のようなラッパーを用意しておくと便利です。

    import { takeEvery, call, race, take } from 'redux-saga/effects';
    
    /**
     * Cancelable takeEvery
     * @example
     * ```
     * yield takeEveryWithCancel({
     *   actionNames: 'START',
     *   callback: taskSaga
     * }, 'STOP')
     * ``` 
     */
    function* takeEveryWithCancel(task: {
      actionNames: string | string[];
      callback: (...args) => void
    }, cancelActionName: string) {
      yield takeEvery(
        task.actionNames,
        function* (...args) {
          yield race({
            task: call(task.callback, ...args),
            cancel: take(cancelActionName),
          });
        }
      );
    }

    使う時はこんな感じで書きます。

    yield takeEveryWithCancel({
      actionNames: START,
      callback: startSaga
    }, STOP)

    参考

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark