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

前端 未结 3 1113
猫巷女王i
猫巷女王i 2020-12-30 23:56

Because \"yield\"-statement isn\'t allowed within a callback, how can i use the \"put\" feature of redux-saga within a callback?

I\'d like to have the following call

相关标签:
3条回答
  • 2020-12-31 00:18

    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);

    0 讨论(0)
  • 2020-12-31 00:20

    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.

    0 讨论(0)
  • 2020-12-31 00:23

    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 component
    handleFileUpload(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

    0 讨论(0)
提交回复
热议问题