我到处搜索,找不到以下答案...
在我的addItemEpic中,我想发送一个" loading"发送ajax请求之前的动作 - 我不希望返回动作的值 - 我只想做动作然后返回ajax响应。 这可以通过store.dispatch()轻松实现,如下所示:
export const addItemsEpic = (action$, store) =>
action$.ofType(ADD_ITEM)
.do(() => store.dispatch({
type: 'layout/UPDATE_LAYOUT',
payload: { loading: true }
}))
.switchMap(action => api.addItem(action.payload))
.map(item => loadItem(item))
.do(() => store.dispatch({
type: 'layout/UPDATE_LAYOUT',
payload: { loading: false }
}))
.catch(error => Observable.of({
type: 'AJAX_ERROR',
payload: error,
error: true
}));
但是不推荐使用store.dispatch(),并且不建议使用redux-observable。
我试图使用几乎所有合理的操作符,但仍然无法在不中断下一个链接函数中的返回值的情况下调度操作。我认为像te一样的事情应该这样做:
action$.ofType(ADD_ITEM)
.concatMap(action => Observable.of(
updateLayout({loading: true}),
api.addItem(action.payload)).last())
.map(item => loadItem(item))
但不幸的是,这里有两个问题:
我非常感谢这里的一些帮助或建议,因为我无法找到任何方法来实现这一目标。
提前致谢
答案 0 :(得分:1)
第二种形式是在正确的道路上。我们的想法是返回首先发出加载操作的Observable
,然后在服务调用之后发出loaded
操作或error
操作,最后发出完成加载操作。< / p>
const addItemEpic = action$ => action$
.ofType(ADD_ITEM)
.switchMap(action => { // or use mergeMap/concatMap depending on your needs
const apiCall$ = Observable.fromPromise(api.addItem(action.payload))
.map(item => actions.loadItem(item))
.catch(err => Observable.of(actions.ajaxError(err)));
return Observable.concat(
Observable.of(actions.updateLayout(true)),
Observable.concat(apiCall$,
Observable.of(actions.updateLayout(false))));
});
Observable.fromPromise()
将Promise
转换为Observable
答案 1 :(得分:1)
很多时候,当你发现自己同步跟随一个又一个动作时,这表明你的减速器只需要第一个。
e.g。除了layout/UPDATE_LAYOUT
设置loading: true
之外,您的减速器可以知道只要有ADD_ITEM
和LOAD_ITEM
,就意味着它应该是loading: true
。如果隐含性不是你的包,那么你可以使用额外的元数据作为信号而不是动作类型本身。
const layoutReducer = (state = { loading: false }, action) => {
// instead of listening for an action type, we're looking for some other
// metadata by convention. In this case the `layout` property.
if (action.layout) {
return { ...state, ...action.layout };
} else {
return state;
}
};
// the schema you use (payload vs layout vs metadata, etc) is your call
store.dispatch({
type: 'DOESNT_MATTER',
payload: 'whatever',
layout: { loading: true }
});
所有这一切,你的例子可能已被简化,以便更容易询问SO(一个好主意)。有时,为了清晰,分离关注点,重新分配,或者仅仅因为你拥有而将它们分开,因为你不控制正在监听它的库,确实有意义。例如react-router-redux
您需要发送特殊操作来进行路由转换。
所以想到这就像“记住”建议而不是教义:)
concat支持任意数量的参数,因此您只需要其中一个参数:
const addItemEpic = action$ => action$
.ofType(ADD_ITEM)
.switchMap(action => {
const apiCall$ = Observable.fromPromise(api.addItem(action.payload))
.map(item => actions.loadItem(item))
.catch(err => Observable.of(actions.ajaxError(err)));
return Observable.concat(
Observable.of(actions.updateLayout(true)),
apiCall$,
Observable.of(actions.updateLayout(false))
);
});
// or
const addItemEpic = action$ => action$
.ofType(ADD_ITEM)
.switchMap(action =>
Observable.concat(
Observable.of(actions.updateLayout(true))
Observable.fromPromise(api.addItem(action.payload))
.map(item => actions.loadItem(item))
.catch(err => Observable.of(actions.ajaxError(err))),
Observable.of(actions.updateLayout(false))
)
);