问题
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