Javascript 如何从redux observable分派多个操作?
我想从redux可观察史诗中分派多个动作。我怎么做?我最初是从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
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为一个伟大的图书馆!