How to coordinate this behavior in react-saga?

Viewed 34

I am saving an entity.

I want to trigger a synchronous savePending (triggers a reducer against the store), and then an asynchronous save operation (makes the network call to make the save).

function * saveEntity({ paylpoad: { id, name } }) {
  yield put (savePending()); // triggers a synchronous reducer
  yield put (save()); // triggers an async saga
  yield put (saveComplete());
}

Will redux-saga wait for savePending to complete (ie. for the reducer to complete running against the store) before moving on to save? (presumably yes).

Will redux-saga wait for all reducers and sagas associated with an action emitted by a put (eg save) even if they are asynchronous, before moving onto the next yield (eg saveComplete)?

1 Answers

Yes, as you expect, the savePending() reducer will run as soon as the put (savePending()) effect is yielded.

On the other hand, no, the yield put (save()) call will not wait for the save to complete.

I imagine you've got code something like this:

const save = () => { type: SAVE_ACTION };

function * watchSave() {
  yield takeEvery(SAVE_ACTION, doSave);
}

function * doSave() {
    // [async saving logic]
}

When you yield your save action, it will trigger a call to your reducer (which will likely do nothing, if your save action is only used to trigger a saga), but there's no way for your saveEntity saga to know to wait for the saveSaga, which was triggered from the save action.

There's a few ways to fix that. One would be to write your code like this:

function * saveEntity({ paylpoad: { id, name } }) {
  yield put (savePending());
  yield call (doSave());
  yield put (saveComplete());
}

By calling the saveSaga() directly, saveEntity will wait for the saveSaga() to complete before moving on.


On the other hand, if you want to keep saveEntity and saveSaga less coupled, you could have saveSaga emit an action which saveEntity can listen for:

function * watchSave() { /* as before */ }

function * doSave() {
  // [async saving logic]
  yield put(saveCompleted()); // Indicate that the save is completed
}

function * saveEntity({ paylpoad: { id, name } }) {
  yield put (savePending());
  yield put (save());
  // Wait for the saveSaga to be done:
  yield take (saveComplete());
}
Related