5

我有一个具有四个 ngrx 操作的 Angular (2) 应用程序:

  • 开始
    • 没有被reducer处理(没有状态改变)
    • ngrx Effect 调用异步任务并映射到 SUCCESS 或 ERROR
  • 成功
    • 由减速机处理
    • ngrx 效果映射到 ADVANCE
  • 进步
    • 不被减速机处理
    • ngrx 效果导航到不同的路线
  • 错误
    • 由减速机处理
    • 没有效果

问题是捕获 ADVANCE 的 Effect 似乎在处理 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在各处添加了语句,输出如下所示:

  1. 成功效应
  2. ADVANCE 效果(显示 route.foo === null)
  3. SUCCESS reducer(显示 route.foo === 东西)
  4. 错误

我希望 SUCCESS 效果和 SUCCESS 减速器在 ADVANCE 效果之前运行。

难道我做错了什么?

期望减速器以与调度相同的顺序处理动作是不正确的吗?


版本:

  • @angular/cli:1.0.0-beta.32.3
  • 节点:7.5.0
  • 操作系统:达尔文 x64
  • @角/普通:2.4.7
  • @角/编译器:2.4.7
  • @角/核心:2.4.7
  • @角/形式:2.4.7
  • @角/http:2.4.7
  • @角/平台浏览器:2.4.7
  • @角/平台浏览器动态:2.4.7
  • @角/路由器:3.4.7
  • @angular/cli:1.0.0-beta.32.3
  • @angular/compiler-cli:2.4.7
  • @ngrx/core@1.2.0
  • @ngrx/效果@2.0.0
  • @ngrx/store@2.2.1
  • rxjs:5.1.1
4

3 回答 3

2

要回答您的结论性问题:

  • 难道我做错了什么?
  • 不,我不认为你做错了什么。
  • 期望减速器以与调度相同的顺序处理动作是不正确的吗?
  • 这个顺序似乎合乎逻辑,但显然你现在不能指望

似乎有一个错误导致了这种行为。您很可能正在经历它,因为您直接映射到另一个动作。通常,如果您有异步操作或类似的操作,reducer 有时间在监听下一个动作的效果开始之前完成。

也许不是您问题的一部分,但您指定问题的解决方案是在有效负载的帮助下直接在成功中导航到您的新路线,或将有效负载传递给 ADVANCE。

下面的链接是与您的相关的效果、商店和 rxjs 项目中报告的问题:

好像他们正在努力:)

于 2017-07-08T23:46:09.687 回答
0

用 .concatMap 替换 START 操作的捕获中的 .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})));
于 2017-07-07T14:01:47.010 回答
-2

ngex/effects 的目的是在基于 redux 的环境中充当中间件。

在此处输入图像描述

所以你在这里基本上做的是调用应该在reducer上工作并继续另一个动作的“成功”动作是中间件。但这就是 effecs 的辅音,它应该拦截动作并自己处理它们,只有在异步处理它之后才调度动作。

那么这里发生了什么?您将成功发送到两个不同的地方,一个应该由减速器处理,一个由中间件处理。我不确定它是否总是这样,但中间件会在到达减速器之前拦截传入的动作。我认为,如果您稍微修改一下代码,它应该可以工作。尝试做类似的事情:

@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})));

你看到我在这里做什么了吗?我已经删除了拦截“成功”的中间件,所以“成功”不会击中减速器。在它发送另一个类型为“advance”的动作之后,该动作应该在“成功”完成处理后命中您的中间件。

希望能帮助到你。

于 2017-03-11T11:25:47.097 回答