I need to cancel a particular task in redux saga from the tasks which r running parallely. with the code below all of the parallel tasks are cancelled

Viewed 74
function* imageUploadfunctionCall(payload) {
  for (let image of payload.payload) {
    const {response, error} = yield call(imageUploadRequest(image))
    if (response) {
      yield put({type: ON_UPLOAD_SUCCESS, payload: image})
    } else if (error) {
      console.log('error', error)
    }
  }
}

export function* watchImageUpload() {
  while (true) {
    let workerTask = yield takeEvery(
      ON_UPLOAD_PROGRESS,
      imageUploadfunctionCall
    )
    yield take(ON_CANCEL_BATCH_UPLOAD)
    yield cancel(workerTask)
  }
}
1 Answers

There is multiple ways you can do this, for example you can use an in-between saga with a race effect:

function* imageUploadfunctionCall(payload) {
  for (let image of payload.payload) {
    const {response, error} = yield call(imageUploadRequest(image))
    if (response) {
      yield put({type: ON_UPLOAD_SUCCESS, payload: image})
    } else if (error) {
      console.log('error', error)
    }
  }
}

function* imageUploadSaga(payload) {
  yield race([
    call(imageUploadfunctionCall, payload),
    take(a => a.type === ON_CANCEL_BATCH_UPLOAD && a.id === payload.id),
  ])
}

export function* watchImageUpload() {
  yield takeEvery(ON_UPLOAD_PROGRESS, imageUploadSaga)
}

The code above assumes that you send an id property for both the ON_UPLOAD_PROGRESS & ON_CANCEL_BATCH_UPLOAD actions so you can identify which one to cancel.

On a side note, in the upload saga you have:

yield call(imageUploadRequest(image))

which should be probably instead

yield call(imageUploadRequest, image)

(unless imageUploadRequest is a function factory).


For more complex cases you could hold a map of tasks & ids.

export function* watchImageUpload() {
  const taskMap = {}

  yield takeEvery(ON_CANCEL_BATCH_UPLOAD, function* (action) {
    if (!taskMap[action.payload]) return
    yield cancel(taskMap[action.payload])
    delete taskMap[action.payload]
  })

  while (true) {
    let payload = yield take(ON_UPLOAD_PROGRESS, imageUploadSaga)
    const workerTask = yield fork(imageUploadfunctionCall, payload)
    taskMap[payload.id] = workerTask
  }
}

Again, you need some id in both actions.

Related