我有一个带有四个ngrx动作的Angular(2)应用程序:
问题是捕获ADVANCE的效果似乎在处理SUCCESS的reducer之前运行
这是效果代码:
@Effect() start$ = this.actions$
.ofType('START')
.map(toPayload)
.switchMap(input => doAsyncTask(input)
.map(result => ({type: 'SUCCESS', payload: result}))
.catch(error => ({type: 'ERROR', payload: error})));
@Effect() success$ = this.actions$
.ofType('SUCCESS')
.map(() => ({type: 'ADVANCE'}));
@Effect({dispatch: false}) advance$ = this.actions$
.ofType('ADVANCE')
.withLatestFrom(this.store$.select(state => state.route))
.map(action_route => action_route[1])
.do(route => this.router.navigate([route.foo.bar]));
我得到的错误是Cannot read property 'bar' of null
。属性foo
由处理SUCCESS的reducer设置。
如果我为SUCCESS效果添加延迟,一切都很好用:
@Effect() success$ = this.actions$
.ofType('SUCCESS')
.delay(1)
.map(() => ({type: 'ADVANCE'}));
但是必须加上这个延迟对我来说没有意义。
我在任何地方都添加了console.log
语句,输出如下所示:
我期望SUCCESS效果和SUCCESS减速器在ADVANCE效果之前运行。
我做错了吗?
期望reducers以与调度它们相同的顺序处理操作是不正确的吗?
版本:
答案 0 :(得分:2)
回答你的结论性问题:
- 我做错了吗?
- 期望reducers以与调度它们相同的顺序处理操作是不正确的吗?
似乎有一个导致此行为的错误。您很可能正在体验它,因为您直接映射到另一个动作。通常,如果您有异步操作或类似的操作,则reducer在听取下一个操作的效果开始之前有时间完成。
也许不是您问题的一部分,但是您指定问题的解决方案是在您的有效负载的帮助下直接在SUCCESS中导航到您的新路由,或者将有效负载传递给ADVANCE。
以下链接是与您相关的效果,存储和rxjs项目中报告的问题:
似乎他们正在努力:)
答案 1 :(得分:0)
使用.concatMap替换START操作的catch中的.map可能会有效,并将你的地图放到SUCCESS和ACTION那里。
@Effect() start$ = this.actions$
.ofType('START')
.map(toPayload)
.switchMap(input => doAsyncTask(input)
.concatMap(result => {
return Observable.from([type: 'SUCCESS', payload: result,
type: 'ADVANCE'])
.catch(error => ({type: 'ERROR', payload: error})));
答案 2 :(得分:-2)
ngex / effects的目的是在基于redux的环境中充当中间件。
所以你在这里做的是调用'success'动作,它应该同时适用于reducer并继续执行另一个动作就是中间件。但这是有效的辅音,它应该拦截动作并自己处理它们,只有在异步处理它才会发送动作。
那么这里发生了什么?你将成功发送到两个不同的地方,一个应该由reducer处理,一个应该由中间件处理。我不确定它是否总是那样,但中间件会在它击中减速器之前拦截进来的动作。我想如果你稍微修改一下你的代码它应该可行。尝试做类似的事情:
@Effect() start$ = this.actions$
.ofType('START')
.map(toPayload)
.switchMap(input => doAsyncTask(input)
.map(result =>{
this.store$.dispatch(
{type: 'SUCCESS',
payload: result
});
this.store$.dispatch(
{type: 'ADVANCE'})
}
.catch(error => ({type: 'ERROR', payload: error})));
你看到我在这里做什么?我删除了拦截“成功”的中间件,所以不是“成功”击中减速器。在它之后,它会发出另一个“提前”类型的动作,这个动作应该在“成功”完成后处理你的中间件。
希望它有所帮助。