ngrx - conditionally stop/remove Effect/Action

泄露秘密 提交于 2019-12-10 23:56:15

问题


I am currently building an application with Ionic2 and ngrx and I am trying to stop certian Actions if there is no network connection.

With stop I mean to somehow make them invisible for other Effects and the store or stop them from further "propagating".

Is there a way to do something like this?

@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() should somehow "remove" the Action from the stream, after that it should be like if the action has never been dispatched. Even the store should not change anything or execute the code that would be executed on this Action.


回答1:


One solution would be to add network online/offline to the state (or have it otherwise available as an observable stream). Then you could use takeUntil in your effects that need to ignore actions when you're offline.

In the spirit of the example above, you could try something like this (untested, but should be close):

// 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;
    }
}

There's an initial filter check with the state just to make sure you're actually online, and then going offline later happens via takeUntil. I also added an additional CANCEL action just to show how to stop the effect for multiple reasons.

Also, the above example assumes a model where effects handle 'request' actions (i.e. commands) and the reducers are pure functions that handle the 'result' actions (i.e. events).

UPDATE 2: Ok, I added a simple isLoading progress flag with a corresponding reducer, as requested. Specifically, the addition of the Observable.concat call wraps the book service query with isLoading state changes. The progress action could also have other progress flags as well, and this example only updates the isLoading property.




回答2:


The only thing I can find is https://github.com/ngrx/effects/blob/master/docs/api.md#utilities. Have you had a look at the unsubscribe stuff.

Edit:

Hey a made a small service that seems to stop all ngrx effects stuff. You would just have to call the method when your app goes offline. Have not really tested it but when I called this in my app it stopped all effects from running. Seems like this is the sort of thing you want to do.

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

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


来源:https://stackoverflow.com/questions/40870990/ngrx-conditionally-stop-remove-effect-action

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!