- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我想从 redux-observable 史诗中分派(dispatch)多个 Action 。我该怎么做?我最初是从
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_CATEGORY_SUCCESS
,还想刷新列表 (GET_CATEGORIES_REQUEST
)。我尝试了很多东西,但总是得到
Actions must be plain objects. Use custom middleware for async actions
例如:
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
等
最佳答案
问题是在你的 switchMap
里面你正在返回一个 Promise,它本身解析为一个 concat Observable; Promise<ConcatObservable>
. switchMap
operator 将监听 Promise,然后按原样发出 ConcatObservable,然后将其提供给 store.dispatch
在 redux-observable 的引擎盖下。 rootEpic(action$, store).subscribe(store.dispatch)
.由于分派(dispatch) Observable 没有意义,这就是为什么您会收到操作必须是普通对象的错误。
您的 epic 发出的内容必须始终是普通的旧 JavaScript 操作对象,即 { type: string }
(除非你有额外的中间件来处理其他事情)
由于 Promises 只发出一个值,我们不能用它们发出两个 Action ,我们需要使用 Observables。因此,让我们首先将我们的 Promise 转换为我们可以使用的 Observable:
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)
现在我们需要将发出单个值的 Observable 映射到多个操作中。 map
运算符不做一对多,相反我们想使用 mergeMap
之一, switchMap
, concatMap
, 或 exhaustMap
.在这种非常特殊的情况下,我们选择哪一个并不重要,因为我们应用它的 Observable(包装了 Promise)只会发出一个值,然后 complete()。也就是说,了解这些运算符之间的区别至关重要,因此一定要花一些时间来研究它们。
我要使用 mergeMap
(同样,在这种特定 情况下无关紧要)。自 mergeMap
期望我们返回一个“流”(一个 Observable、Promise、迭代器或数组)我将使用 Observable.of
为我们要发出的两个 Action 创建一个 Observable。
Observable.from(response)
.mergeMap(() => Observable.of(
{ type: ADD_CATEGORY_SUCCESS },
{ type: GET_CATEGORIES_REQUEST }
))
这两个 Action 将按照我提供的顺序同步和顺序发出。
我们也需要添加错误处理,所以我们将使用 catch
来自 RxJS 的运算符——它与 catch
的区别Promise 上的方法很重要,但超出了这个问题的范围。
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 }
))
})
}
虽然这有效并回答了您的问题,但多个 reducer 可以通过同一个 Action 更改状态,而这通常是一个人应该做的。顺序发出两个 Action 通常是一种反模式。
也就是说,这在编程中很常见,这不是绝对规则。确实有一些时候单独执行更有意义,但它们是异常(exception)。您可以更好地了解这是否是这些异常(exception)情况之一。请记住这一点。
关于javascript - 如何从 redux-observable 调度多个 Action ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47965184/
我是一名优秀的程序员,十分优秀!