Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/446.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何从redux observable分派多个操作?_Javascript_Redux_Rxjs_Redux Observable - Fatal编程技术网

Javascript 如何从redux observable分派多个操作?

Javascript 如何从redux observable分派多个操作?,javascript,redux,rxjs,redux-observable,Javascript,Redux,Rxjs,Redux Observable,我想从redux可观察史诗中分派多个动作。我怎么做?我最初是从 const addCategoryEpic = action$ => { return action$.ofType(ADD_CATEGORY_REQUEST) .switchMap((action) => { const db = firebase.firestore() const user = firebase.auth().currentUser return db

我想从redux可观察史诗中分派多个动作。我怎么做?我最初是从

const addCategoryEpic = action$ => {
  return action$.ofType(ADD_CATEGORY_REQUEST)
    .switchMap((action) => {
      const db = firebase.firestore()
      const user = firebase.auth().currentUser
      return db.collection('categories')
        .doc()
        .set({
          name: action.payload.name,
          uid: user.uid
        })
        .then(() => {
          return { type: ADD_CATEGORY_SUCCESS }
        })
        .catch(err => {
          return { type: ADD_CATEGORY_ERROR, payload: err }
        })
    })
}
现在,我不仅要发送
ADD\u CATEGORIES\u SUCCESS
,还要刷新列表(
GET\u CATEGORIES\u REQUEST
)。我尝试了很多事情,但总是失败

动作必须是普通对象。使用自定义中间件进行异步操作

例如:

const addCategoryEpic = action$ => {
  return action$.ofType(ADD_CATEGORY_REQUEST)
    .switchMap((action) => {
      const db = firebase.firestore()
      const user = firebase.auth().currentUser
      return db.collection('categories')
        .doc()
        .set({
          name: action.payload.name,
          uid: user.uid
        })
        .then(() => {
          return Observable.concat([
            { type: ADD_CATEGORY_SUCCESS },
            { type: GET_CATEGORIES_REQUEST }
          ])
        })
        .catch(err => {
          return { type: ADD_CATEGORY_ERROR, payload: err }
        })
    })
}

或者将
switchMap
更改为
mergeMap
etc

为什么要使用Observable.concat?SwitchMap等待其回调函数中包含值(在本例中为动作数组)的Observable或Promise。因此,不需要在返回的promise成功处理程序中返回Observable。 试试这个:

const addCategoryEpic = action$ => {
  return action$.ofType(ADD_CATEGORY_REQUEST)
    .switchMap((action) => {
      const db = firebase.firestore()
      const user = firebase.auth().currentUser
      return db.collection('categories')
        .doc()
        .set({
          name: action.payload.name,
          uid: user.uid
        })
        .then(() => {
          return ([
            { type: ADD_CATEGORY_SUCCESS },
            { type: GET_CATEGORIES_REQUEST }
          ])
        })
        .catch(err => {
          return { type: ADD_CATEGORY_ERROR, payload: err }
        })
    })
}

我发现我应该使用
observable.fromPromise
创建一个observable,然后使用
flatMap
执行多个操作

const addCategoryEpic = action$ => {
  return action$.ofType(ADD_CATEGORY_REQUEST)
    .switchMap((action) => {
      const db = firebase.firestore()
      const user = firebase.auth().currentUser
      const query = db.collection('categories')
        .doc()
        .set({
          name: action.payload.name,
          uid: user.uid
        })
      return Observable.fromPromise(query)
        .flatMap(() => ([
          { type: ADD_CATEGORY_SUCCESS },
          { type: GET_CATEGORIES_REQUEST }
        ]))
        .catch(err => {
          return { type: ADD_CATEGORY_ERROR, payload: err }
        })
    })
}

你也可以尝试在你的史诗中使用商店

const addCategoryEpic = (action$, store) => {
  return action$.ofType(ADD_CATEGORY_REQUEST)
    .switchMap((action) => {
      const db = firebase.firestore()
      const user = firebase.auth().currentUser
      const query = db.collection('categories')
        .doc()
        .set({
          name: action.payload.name,
          uid: user.uid
        })
       return Observable.fromPromise(query)
    }).map((result) => {
      store.dispatch({ type: ADD_CATEGORY_SUCCESS });
      return ({ type: GET_CATEGORIES_REQUEST })
   })
  .catch(err => {
     return { type: ADD_CATEGORY_ERROR, payload: err }
   })
}

问题在于,在
开关映射中,您返回了一个承诺,而这个承诺本身就是一个可观察的concat<代码>承诺
switchMap
操作员将听取承诺,然后按原样发出ConcatObservable,然后将其提供给
存储。通过redux observable在引擎盖下调度<代码>rootEpic(action$,store).订阅(store.dispatch)
。由于分派一个可观察对象是没有意义的,这就是为什么您会得到这样一个错误:操作必须是普通对象

epic发出的内容必须始终是普通的旧JavaScript操作对象,即
{type:string}
(除非您有额外的中间件来处理其他事情)

因为承诺只会发出一个值,所以我们不能用它们发出两个动作,我们需要使用可观测值。因此,让我们首先将我们的承诺转化为我们可以使用的可观察的:

const response = db.collection('categories')
  .doc()
  .set({
    name: action.payload.name,
    uid: user.uid
  })

// wrap the Promise as an Observable
const result = Observable.from(response)
现在我们需要将可观察到的,将发出单个值的,映射到多个动作中。
map
操作符不执行一对多操作,而是希望使用
mergeMap
switchMap
concatMap
exhaustMap
中的一种。在这个非常特殊的情况下,我们选择哪一个并不重要,因为我们应用它的可观察对象(包装承诺)只会发出一个值,然后完成()。也就是说,理解这些操作符之间的差异是至关重要的,所以一定要花一些时间来研究它们

我将使用
mergeMap
(同样,在这种特定情况下这并不重要)。由于
mergeMap
期望我们返回一个“流”(可观察的、承诺的、迭代器或数组),我将使用
observatable.of
来创建我们想要发出的两个动作的可观察的

Observable.from(response)
  .mergeMap(() => Observable.of(
    { type: ADD_CATEGORY_SUCCESS },
    { type: GET_CATEGORIES_REQUEST }
  ))
这两个动作将按照我提供的顺序同步和顺序发出

我们还需要添加回错误处理,因此我们将使用RxJS中的
catch
操作符——它与Promise中的
catch
方法之间的差异很重要,但超出了这个问题的范围

Observable.from(response)
  .mergeMap(() => Observable.of(
    { type: ADD_CATEGORY_SUCCESS },
    { type: GET_CATEGORIES_REQUEST }
  ))
  .catch(err => Observable.of(
    { type: ADD_CATEGORY_ERROR, payload: err }
  ))
把它们放在一起,我们会有这样的东西:

const addCategoryEpic = action$ => {
  return action$.ofType(ADD_CATEGORY_REQUEST)
    .switchMap((action) => {
      const db = firebase.firestore()
      const user = firebase.auth().currentUser
      const response = db.collection('categories')
        .doc()
        .set({
          name: action.payload.name,
          uid: user.uid
        })

      return Observable.from(response)
        .mergeMap(() => Observable.of(
          { type: ADD_CATEGORY_SUCCESS },
          { type: GET_CATEGORIES_REQUEST }
        ))
        .catch(err => Observable.of(
          { type: ADD_CATEGORY_ERROR, payload: err }
        ))
    })
}

虽然这可以解决您的问题,但多个简化程序可以从同一个操作中进行状态更改,这通常是您应该做的。连续发出两个动作通常是反模式

这就是说,正如编程中常见的那样,这不是一条绝对的规则。当然,有时采取单独的行动更有意义,但它们是例外。您可以更好地了解这是否属于例外情况。请记住这一点。

对于RxJs6:

action$.pipe(
  concatMap(a => of(Action1, Action2, Action3))
)

请注意,我们有
concatMap
mergeMap
switchMap
可以完成这项工作,区别在于:

我尝试过这个,但它仍然给出了“操作必须是普通对象。使用自定义中间件进行异步操作”调用
存储。从epic内部发出的调度现在不推荐,现在将被删除,请不要这样做:)Thx为一个伟大的图书馆!