4

I am using saga eventChannel to listen to events that are being triggered(maybe WebSocket in the actual app), and then I am updating my Redux Store. In component, I am calling an API action. Then an interval(polling), which is being handled by a saga. I am attaching my event listener once API succeeded for the first time.

After 2nd API call my eventChannel is terminated somehow.

EventListner:

function* countDownSaga(value) {
  const chan = yield call(countdown, value)
  try {    
    while (true) {
      // take(END) will cause the saga to terminate by jumping to the finally block
      let seconds = yield take(chan)
      console.log(`countdown: ${seconds}`)
    }
  } finally {
    console.log('countdown terminated')
  }
}

Api saga:

var countDownStarted = false

// Function to be called by saga taking action CALL_FAKE_API
function* fetchData() {
  // Simulate some server delay
  yield delay(1500)
  // Call a function
  // redux-saga "call" effect allows you to call a function
  const result = yield call(getUserData)
  yield put({ type: RECORD_USER, result })
  if(!countDownStarted) {
        yield fork(countDownSaga, 100)
        countDownStarted= true
  }
}

Jsfiddle: https://jsfiddle.net/2d9L8fse/2/

Łukasz D. Tulikowski
  • 1,440
  • 1
  • 17
  • 36
sahil solanki
  • 507
  • 6
  • 20

1 Answers1

2

Actually it is not the event channel that is terminated, it goes to the finally block because the saga itself is canceled. That is because you use takeLatest to run the fetchData saga:

yield takeLatest(CALL_FAKE_API, fetchData)

And in your react component you are dispatching the CALL_FAKE_API action every 15 seconds:

componentDidMount() {
      const { callFakeApi } = this.props
      callFakeApi()
      this.timer = setInterval(function () { callFakeApi() }, 15 * 1000)
}

If one fetchData saga is already running and you dispatch the CALL_FAKE_API again, takeLatest will cancel the previous saga - including all its attached children like the countDownSaga saga.

You can try e.g. replacing the fork effect with spawn which creates a detached task, that is not canceled even if the fetchData saga is canceled.

yield spawn(countDownSaga, 100)

If you don't need to cancel the fetch itself, you can also just replace takeLatest with takeEvery and avoid the cancelation altogether.

Martin Kadlec
  • 4,702
  • 2
  • 20
  • 33