ngrx - 有条件地停止/删除效果/动作

时间:2016-11-29 16:34:00

标签: angular redux ionic2 rxjs ngrx

我目前正在使用Ionic2和ngrx构建应用程序,如果没有网络连接,我正在尝试停止certian操作。

有了停止,我的意思是以某种方式使它们对其他效果和商店不可见或阻止它们进一步“传播”。

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

@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()应该以某种方式从流中“删除”Action,之后应该就像是从未调度过该动作一样。即使是商店也不应该更改任何内容或执行将在此Action上执行的代码。

2 个答案:

答案 0 :(得分:7)

一种解决方案是将网络在线/离线添加到州(或者将其作为可观察流提供)。然后,您可以在效果中使用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属性。

答案 1 :(得分: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();
    }
}