【问题标题】:Redux saga, axios and progress eventRedux saga、axios 和进度事件
【发布时间】:2016-11-03 13:28:41
【问题描述】:

是否有干净/简短/正确的方式来一起使用 axios 承诺和上传进度事件?

假设我有下一个上传功能:

function upload(payload, onProgress) {
  const url = '/sources/upload';

  const data = new FormData();

  data.append('source', payload.file, payload.file.name);

  const config = {
    onUploadProgress: onProgress,
    withCredentials: true
  };

  return axios.post(url, data, config);
}

这个函数返回了承诺。

我还有一个传奇:

function* uploadSaga(action) {
  try {
    const response = yield call(upload, payload, [?? anyProgressFunction ??]);
    yield put({ type: UPLOADING_SUCCESS, payload: response });
  } catch (err) {
    yield put({ type: UPLOADING_FAIL, payload: err });
  }
}

我想接收进度事件并将其放在 saga 中。我还想捕捉 axios 请求的成功(或失败)结果。有可能吗?

谢谢。

【问题讨论】:

    标签: reactjs redux redux-saga


    【解决方案1】:

    所以我找到了答案,感谢Mateusz Burzyński 的澄清。

    我们需要使用 eventChannel,但有点不习惯。

    假设我们有上传文件的api函数:

    function upload(payload, onProgress) {
      const url = '/sources/upload';
    
      const data = new FormData();
    
      data.append('source', payload.file, payload.file.name);
    
      const config = {
        onUploadProgress: onProgress,
        withCredentials: true
      };
    
      return axios.post(url, data, config);
    }
    

    在 saga 中我们需要创建 eventChannel 但将 emit 放在外面。

    function createUploader(payload) {
    
      let emit;
      const chan = eventEmitter(emitter => {
    
        emit = emitter;
        return () => {}; // it's necessarily. event channel should 
                         // return unsubscribe function. In our case 
                         // it's empty function
      });
    
      const uploadPromise = upload(payload, (event) => {
        if (event.loaded.total === 1) {
          emit(END);
        }
    
        emit(event.loaded.total);
      });
    
      return [ uploadPromise, chan ];
    }
    
    function* watchOnProgress(chan) {
      while (true) {
        const data = yield take(chan);
        yield put({ type: 'PROGRESS', payload: data });
      }
    }
    
    function* uploadSource(action) {
      const [ uploadPromise, chan ] = createUploader(action.payload);
      yield fork(watchOnProgress, chan);
    
      try {
        const result = yield call(() => uploadPromise);
        put({ type: 'SUCCESS', payload: result });
      } catch (err) {
        put({ type: 'ERROR', payload: err });
      }
    }
    

    【讨论】:

    • 应该将 eventEmitter 改为 eventChannel 吗?
    【解决方案2】:

    我个人发现接受的答案非常复杂,我很难实现它。其他 google / SO 搜索都导致类似类型的答案。如果它对你有用,那就太好了,但我找到了另一种使用 EventEmitter 的方法,我个人觉得更简单。

    在代码中的某处创建事件发射器:

    // emitter.js
    
    import { EventEmitter } from "eventemitter3";
    
    export default new EventEmitter();
    

    在您的 saga 中进行 api 调用,使用此发射器在 onUploadProgress 回调中发出事件:

    // mysagas.js
    import eventEmitter from '../wherever/emitter';
    
    function upload(payload) {
      // ...
    
      const config = {
        onUploadProgress: (progressEvent) = {
          eventEmitter.emit(
            "UPLOAD_PROGRESS", 
            Math.floor(100 * (progressEvent.loaded / progressEvent.total))
          );
        }
      };
    
      return axios.post(url, data, config);
    }
    

    然后在你需要这个上传进度号的组件中,你可以在mount时监听这个事件:

    // ProgressComponent.jsx
    import eventEmitter from '../wherever/emitter';
    
    const ProgressComponent = () => {
    
      const. [uploadProgress, setUploadProgress] = useState(0);
    
      useEffect(() => {
        eventEmitter.on(
          "UPLOAD_PROGRESS",
          percent => {
            // latest percent available here, and will fire every time its updated
            // do with it what you need, i.e. update local state, store state, etc
            setUploadProgress(percent)
          }
        );
      
        // stop listening on unmount
        return function cleanup() {
          eventEmitter.off("UPLOAD_PROGRESS")
        }
      }, [])
    
      return <SomeLoadingBar value={percent} />
    
    }
    

    这对我有用,因为我的应用程序已经出于其他原因使用了全局 eventEmitter。我发现这更容易实现,也许其他人也会。

    【讨论】:

    • 这太棒了!惊人的!如此干净和容易!
    猜你喜欢
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    • 2019-06-08
    • 2021-09-20
    相关资源
    最近更新 更多