Infinite loop with redux-saga

I know you found your answer, that's great. I had the same symptoms but a different problem and a different solution.

I am not using normal constants for my actions, I am using the constants from my actions so that I only need to write it in a single location. It's a setup I have. However I realised an issue today. My code looks like the following

    export const deleteArendeAction = {
      will: arende => ({
        type: "WILL_TA_BORT_ARENDEN",
        ...arende,
      }),
      did: payload => ({
        type: "DID_TA_BORT_ARENDEN",
        ...payload,
      }),
      error: payload => ({
        type: "DID_DELETE_ARENDE_ERROR",
        ...payload,
      }),
    }

    function* deleteArenden(arende) {
      try {
        yield arendeApi.deleteArende(arende.id)
      } catch (error) {
        yield put(deleteArendeAction.error(arende))
        return
      }
      yield put(deleteArendeAction.did(arende))
    }

    export function* deleteArendeSaga() {
        yield takeEvery(deleteArendeAction.will().type, deleteArenden)
    }

My code looks something like that. It kept triggering my takeEvery infinitely. It turns out, yield put(deleteArendeAction.did(arende)) this part was the culprit. Because the variable arende had the value of { type: "WILL_TA_BORT_ARENDEN", ... } which caused some sort of bug, triggering the event again. Technically, that shouldn't happen I think? But it did. So if you come across this question and the answer doesn't solve your problem. Then double-check what you send into your put :P


Of course, you explicitly set the infinite loop the next lines:

yield put({type: 'SHOW_DETAIL', response: response.data})
// ...
yield takeEvery('SHOW_DETAIL', fetchDetailsAsync)

The saga doesn't do any magic things for you, and only is a preliminary layer of a subscription and generation on actions and executions coroutines.

SOLUTION:

You shall use different names for actions which you catch from React components, and actions which are used for optimistical and real up-dating of a status.

Use yield takeEvery('SHOW_DETAIL_REQUEST', fetchDetailsAsync) and name your action in this manner.

Use yield put({type: 'SHOW_DETAIL_SUCCESS', response: response.data}) in success response and name your reducer in this manner

More than that, you can use 'SHOW_DETAIL_FAILURE' for failed saga request.

All names above are common-used case.