2016-11-29 46 views
2

我目前正在用Ionic2和ngrx构建一个应用程序,如果没有网络连接,我试图停止certian操作。ngrx - 有条件停止/删除效果/动作

随着停止我的意思是以某种方式使他们对其他效果和商店隐形或阻止他们进一步“传播”。

有没有办法做这样的事情?从流

@Effect() 
checkNetworkConnection$ = this.actions$ 
    .ofType(book.ActionTypes.LOAD_BOOKS, book.ActionTypes.CREATE_BOOK) 
    .if(Network.connection === 'none') 
    .do(() => new ShowNetworkAlertAction()) //Returns ShowNetworkAlertAction 
    .stopPropagation(); // Removes the Action from the stream 

stopPropagation()应该以某种方式“删除”的行动,在这之后应该是这样,如果行动从来没有被派遣。即使商店不应该改变任何东西或执行将在这个行动上执行的代码。

+0

你的意思是,['filter'](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-filter)? – paulpdaniels

+0

@paulpdaniels不,我想要一些事情,如果一个行动派遣,然后从流中删除此操作(没有其他效果或减速器应该对此行动作出反应) – Daskus

+0

我的理解是,影响接收已* *已*的行动分发到商店,因此当没有网络连接时,您不能使用效果来阻止LOAD_BOOKS和CREATE_BOOK行为的传播。效应是行动的来源;他们不是行为过滤器。 – cartant

回答

0

我唯一能找到的就是https://github.com/ngrx/effects/blob/master/docs/api.md#utilities。你有没有看过取消订阅的东西。

编辑:

嘿嘿一做了一个小的服务,似乎停止所有NGRX效果的东西。您只需在应用下线时调用该方法。还没有真正测试过它,但是当我在应用程序中调用它时,它停止了运行的所有效果。看起来像这是你想要做的事情。

import {EffectsSubscription} from "@ngrx/effects" 
import {Injectable} from "@angular/core" 
@Injectable() 
export class EffectsOffline 
{ 
    constructor(private subscription: EffectsSubscription) 
    { 
    } 

    stopPropagation() 
    { 
     this.subscription.unsubscribe(); 
    } 
} 
+0

是的,但我不知道如何将其用于我的用例。 – Daskus

+0

感谢您的回答,但也许我错过了说我想停止行动本身。另一件事是,我只是想停止certian行动,并不是所有的人,因为这将打破整个应用程序 – Daskus

6

一种解决方案是将网络在线/离线添加到状态(或者使其作为可观察流可用)。然后,您可以在需要忽略脱机时的操作的效果中使用takeUntil

在上面的例子中的精神,你可以尝试这样的事情(未经测试,但应接近):

// NOTE: This effect listens for `LOAD_BOOKS` command actions, and emits the 
// `PROGRESS` and either `LOAD_BOOKS_SUCCESS` or `LOAD_BOOKS_FAILURE` event actions 
// that the reducers will listen for. 
@Effect() 
loadBooksWhenOnline$ = this.actions$ 
    .ofType('LOAD_BOOKS') 
    .map(action => action.payload) 
    .withLatestFrom(this.store$) 
    .filter(([payload, state]) => state.network.status === 'online') 
    .switchMap(([payload, state]) => { 
     const networkOffline$ = this.actions$.ofType('NETWORK') 
      .filter(action => action.payload === 'offline'); 

     const someOtherReasonToCancel$ = this.actions$.ofType('CANCEL'); 

     const stop$ = Observable.merge(networkOffline$, someOtherReasonToCancel$); 

     return Observable.concat(
      Observable.of({ type: 'PROGRESS', payload: { isLoading: true } }), 
      this.bookService.getBooks$(payload) 
       .map(books => ({ type: 'LOAD_BOOKS_SUCCESS', payload: books })) 
       .catch(err => Observable.of({ type: 'LOAD_BOOKS_FAILURE', payload: { payload, err }) 
       .takeUntil(stop$), 
      Observable.of({ type: 'PROGRESS', payload: { isLoading: false } }), 
     ); 
    }) 
    .observeOn(async); // may want this, depending on how your actions interact 

// elsewhere in reducerville 
export function reducer(state, action) { 
    switch (action.type) { 
     case 'LOAD_BOOKS_SUCCESS': 
      return reduceLoadBooksSuccessAction(state, action); 
     case 'LOAD_BOOKS_FAILURE': 
      return reduceLoadBooksFailureAction(state, action); 
     case 'PROGRESS': 
      return Object.assign({}, state, { 
       progress: Object.assign({}, state.progress, action.payload) 
      }); 
     // ... 
     default: 
      return state; 
    } 
} 

有最初的过滤器检查与国家只是为了确保你实际上是在线,然后再通过takeUntil进入离线状态。我还添加了一个额外的CANCEL操作,只是为了说明如何停止效果的原因有很多。另外,上面的例子假定一个模型,其中处理'请求'动作(即命令)和减速器是处理'结果'动作(即事件)的纯函数。

更新2:好的,我添加了一个简单的isLoading进度标志与相应的reducer,根据要求。具体而言,Observable.concat调用的添加包含了isLoading状态更改的书籍服务查询。进度操作也可以包含其他进度标志,并且此示例仅更新isLoading属性。

+0

看起来不错!但是LOAD_BOOKS行动还在进入减速器吗?这将是一个问题,因为这个动作可能会改变状态并设置一个不会被设置为false的'{loading:true}'标志 – Daskus

+0

对不起,我应该已经显示将书服务的结果包装为发出减速器正在观看的事件。这个想法是,效果监听请求,但减法器只监听请求的结果。我会尽力更新它。 – rob3c

+0

@Daskus我添加了一些简单的成功/失败事件映射从书服务observable,以及相应的样本减速器代码。让我知道如果它清除它。这种异步设置的主要思想是区分效应(副作用)和reducer(纯函数)。 – rob3c