How to "yield put" in redux-saga within a callback? How to "yield put" in redux-saga within a callback? javascript javascript

How to "yield put" in redux-saga within a callback?


One possible solution, as you already mentioned, is to use channels. Here is an example that should work in your case:

import { channel } from 'redux-saga'import { put, take } from 'redux-saga/effects'const downloadFileChannel = channel()export function* loadFile(id) {  ...  const download = RNFS.downloadFile({     ...     // push `S_PROGRESS` action into channel on each progress event     progress: (progress) => downloadFileChannel.put({       type: ACTIONS.S_PROGRESS,       progress,     }),  })  ...}export function* watchDownloadFileChannel() {  while (true) {    const action = yield take(downloadFileChannel)    yield put(action)  }}

The idea here is that we will push a S_PROGRESS action on the channel for each progress event that is emitted from RNFS.downloadFile.

We also have to start another saga function that is listening to each pushed action in a while loop (watchDownloadFileChannel). Everytime an action has been taken from the channel, we use the normal yield put to tell redux-saga that this action should be dispatched.

I hope this answer will help you.


I got myself into a similar situation this week.

My solution was to call a dispatch inside the callback and pass the result.

I was handling file uploads so wanted to do a readAsArrayBuffer() call, initially in my saga something like this:

function* uploadImageAttempt(action) {  const reader = new FileReader();  reader.addEventListener('loadend', (e) => {    const loadedImage = reader.result;    yield put(Actions.uploadImage(loadedImage)); // this errors, yield is not allowed  });  reader.readAsArrayBuffer(this.refs[fieldName].files[0]);}

How I got round this was by doing the readAsArrayBuffer() in my component, then call a connected dispatch function:

// in my file-uploader componenthandleFileUpload(e, fieldName) {  e.preventDefault();  const reader = new FileReader();  reader.addEventListener('loadend', (e) => {    const loadedImage = reader.result;    this.props.uploadFile(      this.constructDataObject(),      this.refs[fieldName].files[0],      loadedImage    );  });  reader.readAsArrayBuffer(this.refs[fieldName].files[0]);}...const mapDispatchToProps = (dispatch) => {  return {    uploadFile: (data, file, loadedImage) => {      dispatch(Actions.uploadFile(data, file, loadedImage))    }  }}

Hope that helps


Beside using channel as @Alex suggest, one might also consider using call from 'redux-saga/effects'. The call effect take a function or Promise.

import { call } from 'redux-saga/effects';// ...yield call(download.promise);