Search code examples
redux-saga

takeSequential in redux-saga?


I have a basic saga that looks like this:

const mySaga = function* () {
    yield takeEvery("SOME_ACTION_REQUEST", function* (action) {

        const result = yield call(makeApiCall, action.payload); 
        yield put({
            type: "SOME_ACTION_SUCCESS", 
            payload: result
        }); 

    });  
}

Now the problem I'm having is that if I have two "SOME_ACTION_REQUEST" dispatched simultaneously, then I have a situation where the redux call stack looks like:

SOME_ACTION_REQUEST
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
SOME_ACTION_SUCCESS

And this is screwing up the logic in my reducer.

What I want, is for every request to be run, but for it to wait for the previous one to have completed before it starts.

ie. so it would look like:

SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS
SOME_ACTION_REQUEST
SOME_ACTION_SUCCESS

How would I achieve this?


Solution

  • The actionChannel effect can be used to achieve this.

    See: https://redux-saga.js.org/docs/api/#actionchannelpattern-buffer

    const mySaga = function* () {
        const channel = yield actionChannel("SOME_ACTION_REQUEST"); 
        while (true) {
            const action = yield take(channel); 
            const result = yield call(makeApiCall, action.payload); 
            yield put({
                type: "SOME_ACTION_SUCCESS", 
                payload: result
            }); 
        }
    }
    

    Explanation:

    My understanding is that the actionChannel effect is just going to route all of the incoming requests matching that pattern into a queue.

    The take effect is going to pop them off.

    Putting it all in a while(true) loop means that the actions will be popped off one at a time, and they need to wait to resolve all of the rest of the things (the API calls) before the next one can be called.

    One thing to note about this pattern, is that in redux-dev-tools, the redux stack is still going to look like:

    SOME_ACTION_REQUEST
    SOME_ACTION_REQUEST
    SOME_ACTION_SUCCESS
    SOME_ACTION_SUCCESS
    

    because the requests immediately are added to the channel and remain inactive until they're popped off.