Because you can only add a yield expression in a generator body it can be tricky to use a callback-based library in your saga (a generator function). Let’s take this basic example where we want to dispatch an ERROR or a SUCCESS depending on the result of callbackBasedFn to continue our workflow.

You cannot write the following code because a yield expression is only allowed in a generator body.

import { put } from 'redux-saga/effects';

function* mySaga(input) {
  callbackBasedFn(input, (err, data) => {
    if (err) {
     // Not valid: A 'yield' expression is only allowed in a generator body.
      yield put({ type: 'ERROR', err });
    }

 // Not valid: A 'yield' expression is only allowed in a generator body.
    yield put({ type: 'SUCCESS', data });
  });
}

A solution is to use a channel which kind of acts as a watcher.

import { put, take } from 'redux-saga/effects';
import { channel } from 'redux-saga';

function* mySaga(input) {
  const callbackChannel = channel();
  callbackBasedFn(input, (err, data) => {
    if (err) {
      callbackChannel.put({ type: 'ERROR', err });
    }

    callbackChannel.put({ type: 'SUCCESS', data });
  });
  
  const action = yield take(callbackChannel);
  yield put(action);
}