【问题标题】:How to "yield put" in redux-saga within a callback?如何在回调中在 redux-saga “yield put”?
【发布时间】:2017-08-19 07:12:31
【问题描述】:

由于回调中不允许使用“yield”-statement,我如何在回调中使用 redux-saga 的“put”功能?

我想要以下回调:

function onDownloadFileProgress(progress) {
  yield put({type: ACTIONS.S_PROGRESS, progress})
}

这不起作用并以“意外令牌”告终,因为 yield 在普通函数中是不允许的。否则我不能将回调作为“function *”传递,这将允许屈服。 ES6 在这里似乎坏了。

我读到 redux-saga 提供了一些称为“channels”的功能,但说实话,我没有明白。我已经多次阅读这些渠道和示例代码,但在所有示例中,它们都解决了非常困难和不同的问题,而不是我的简单案例,最终我已经站起来了。

谁能告诉我如何处理这个问题?

整个上下文:

function onDownloadFileProgress(progress) {
  yield put({type: ACTIONS.S_PROGRESS, progress})
}

export function * loadFile(id) {
  let url = `media/files/${id}`;

  const tempFilename = RNFS.CachesDirectoryPath + '/' + id;

  const download = RNFS.downloadFile( {
    fromUrl: url,          
    toFile: tempFilename,  
    background: false,
    progressDivider: 10,
    progress: onDownloadFileProgress,
  })

  yield download.promise;

}

【问题讨论】:

  • 不允许你不能
  • 你想说什么?有什么不同吗?

标签: javascript ecmascript-6 redux yield redux-saga


【解决方案1】:

正如您已经提到的,一种可能的解决方案是使用channels。这是一个应该适用于您的情况的示例:

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

这里的想法是,对于从RNFS.downloadFile 发出的每个进度事件,我们将在通道上推送一个S_PROGRESS 操作。

我们还必须启动另一个 saga 函数,它在 while 循环 (watchDownloadFileChannel) 中监听每个推送的操作。每次从频道执行操作时,我们都会使用普通的 yield put 告诉 redux-saga 应该调度该操作。

希望这个回答对你有所帮助。

【讨论】:

  • 效果很好!非常感谢!
  • 这似乎是我类似问题的解决方案,但我遇到了通道缓冲区溢出。你是如何将watchDownloadFileChannel 连接到 sagaMiddleware 的?
  • 谢谢!这帮助我让 socket.io 以更简洁的方式与 redux-saga 一起工作
  • 如何将watchDownloadFileChannel 连接到 saga 中间件?
  • 好的,谁想知道如何连接watchDownloadChannel。您可以简单地导出此代码takeEvery(channel, watchDownloadChannel) 并将其导入rootSaga
【解决方案2】:

这周我也陷入了类似的境地。

我的解决方案是在回调中调用调度并传递结果。

我正在处理文件上传,所以想做一个readAsArrayBuffer() 调用,最初在我的传奇中是这样的:

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

我解决这个问题的方法是在我的组件中执行readAsArrayBuffer(),然后调用连接的调度函数:

// 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))
    }
  }
}

希望有帮助

【讨论】:

    【解决方案3】:

    除了按照@Alex 的建议使用channel 之外,还可以考虑使用'redux-saga/effects' 中的callcall 效果采用函数或Promise

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

    【讨论】:

      【解决方案4】:

      这是最简单的方法:

      import store from './store' // import redux store
      store.dispatch(your action creator here)
      

      【讨论】:

        猜你喜欢
        • 2017-06-14
        • 1970-01-01
        • 2021-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-25
        相关资源
        最近更新 更多