Redux-Observable multiple actions in single epic

2019-08-30 06:29发布

问题:

I'm new to this and there are several similar questions such as redux-observable - dispatch multiple redux actions in a single epic but I can't see how they apply to my usecase.

I'm using a Subject to emit multiple events based on processing a file and uploading to a server

export function UploadSceneWithFile(scene){

  const subject$ = new Subject()

  FileToScenePreview(scene,scene.file).then(res => subject$.next(res))

  const uploader = new S3Upload({
   ....
    onError:()=>subject$.next('error'),
    onProgress: (val)=> subject$.next(val),
    onFinishS3Put: ()=>subject$.next('complete'),
  })
  uploader.uploadFile(scene.file)

  return subject$
}

A want to write an epic that captures these events and dispatches actions based on the data coming back.

ie. something like this

export function uploadSceneFile(action$) {
  return action$.ofType(CREATE_SCENE_SUCCESS)
    .mergeMap(({payload}) =>
      UploadSceneWithFile(payload)
        .subscribe(res => {
            console.log(res)
          if (!res.thumbName) {
            return { type: UPLOAD_SCENE_FAILED, message: 'failed' }
          } else {
            return {type: UPLOAD_SCENE_SUCCESS, payload:  res }
          }
        if (!res.value) {
            return { type: UPLOAD_SCENE_THUMB_FAILED, message: 'failed' }
          } else {
            return {type: UPLOAD_SCENE_THUMB_SUCCESS, payload:  res }
          }
        })
    )
}

I'm getting this error:

TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

i can console log the results OK, but I'm not dispatching any actions.. any ideas how I go about this?

回答1:

What's happening is that you're returning a subscription inside your mergeMap, instead of an Observable that it expects. Instead of using subscribe it looks like you want to use map

export function uploadSceneFile(action$) {
  return action$.ofType(CREATE_SCENE_SUCCESS)
    .mergeMap(({payload}) =>
      UploadSceneWithFile(payload)
        .map(res => { // <------------------ map, not subscribe
            console.log(res)
          if (!res.thumbName) {
            return { type: UPLOAD_SCENE_FAILED, message: 'failed' }
          } else {
            return {type: UPLOAD_SCENE_SUCCESS, payload:  res }
          }
        if (!res.value) {
            return { type: UPLOAD_SCENE_THUMB_FAILED, message: 'failed' }
          } else {
            return {type: UPLOAD_SCENE_THUMB_SUCCESS, payload:  res }
          }
        })
    )
}

In redux-observable you will almost never call subscribe yourself, instead composing Observables. The only time you'd use it is mostly with custom operators that aren't super common.