2016-09-19 18 views
16

ja aktualizowania @ngrx/effects od 1.x do 2.xJak uzyskać dostęp do drzewa stanu w efektach? (@ Ngrx/Efekty 2.x)

W 1.x mam dostęp drzewa państwowej w działaniu:

constructor(private updates$: StateUpdates<AppState>) {} 

    @Effect() bar$ = this.updates$ 
    .whenAction(Actions.FOO) 
    .map(obj => obj.state.user.isCool) 
    .distinctUntilChanged() 
    .filter(x => x) 
    .map(() => ({ type: Actions.BAR })); 

teraz w 2 .x, daje mi tylko akcję. Czy istnieje jeszcze sposób na uzyskanie dostępu do drzewa stanu? Czy powinienem unikać używania tego w ten sposób, ponieważ nie jest to dobra praktyka?

constructor(private actions$: Actions) {} 

    @Effect() bar$ = this.actions$ 
    .ofType(ActionTypes.FOO) 
    .map((obj: any) => { 
     console.log(obj);    // here is action only 
     return obj.state.user.isCool // so it is wrong here 
    }) 
    .distinctUntilChanged() 
    .filter(x => x) 
    .map(() => ({ type: ActionTypes.BAR })); 

Odpowiedz

19

Innym sposobem jest użycie .withLatestFrom(this.store). Kompletny kod to:

constructor(
    private actions$: Actions, 
    private store: Store<AppState> 
) {} 

@Effect() bar$ = this.actions$ 
    .ofType(ActionTypes.FOO) 
    .withLatestFrom(this.store, (action, state) => state.user.isCool) 
    .distinctUntilChanged() 
    .filter(x => x) 
    .map(() => ({ type: ActionTypes.BAR })); 
+1

Ponadto, jeśli używasz 'this.store.select (fromRoot.getUserIsCool)' nie musisz używać 'distinctUntilChanged()' ... prawda? – Helzgate

+0

Przekazywanie magazynu do 'withLatestFrom' wyrzuca' TypeError: Podałeś niepoprawny obiekt, w którym oczekiwano strumienia. Możesz zapewnić Observable, Promise, Array lub Iterable. ". To działa. Każdy pomysł, dlaczego dostaję błąd? –

4

Efekty nie muszą być właściwościami klasy; Mogą to być również metody. Co oznacza, że ​​możesz uzyskać dostęp do sklepu, który jest wstrzykiwany do konstruktora.

W chwili pisania tego odpowiedź, semantyka oświadczeniach majątkowych ipublic/privateparametry konstruktora nie były dla mnie jasne. Jeśli właściwości są zadeklarowane po konstruktorze, mogą uzyskać dostęp do elementów zadeklarowanych za pomocą parametrów konstruktora - więc nie trzeba zadeklarować swoich efektów jako funkcji.

Z zatłoczonego sklepu, powinieneś być w stanie korzystać z operatorem jak mergeMap aby uzyskać stan i połączyć je z aktualizacją otrzymanej:

@Effect() 
bar$(): Observable<Action> { 

    return this.actions$ 
    .ofType(ActionTypes.FOO) 
    .mergeMap((update) => this.store.first().map((state) => ({ state, update }))) 
    .map((both) => { 
     // Do whatever it is you need to do with both.update and both.state. 
     return both.update; 
    }) 
    .distinctUntilChanged() 
    .filter(x => x) 
    .map(() => ({ type: ActionTypes.BAR })); 
    } 
} 

, czy to robi dobrą praktyką jest kwestia opinii, tak myślę. Odczytanie stanu - najlepiej poprzez komponowanie selektora w stylu ngrx - brzmi rozsądnie, ale byłoby czystsze, gdyby wszystkie informacje potrzebne do określonego efektu zostały uwzględnione w akcjach, do których nasłuchiwał.

+0

Edytowałem swoją odpowiedź. Przetestowałem to, co napisałem - z góry mojej głowy - i moja aplikacja popadła w szał, ponieważ "combineLatest" spowodował cykl aktualizacji stanu. Dodano komentarz dotyczący: dobrej praktyki. – cartant

+1

dziękuję bardzo! Twoja pierwsza próba idzie w dobrym kierunku, potrzebujesz zmiany na 'withLatestFrom' –

+1

Tak, 'withLatestFrom' jest znacznie lepszym rozwiązaniem. – cartant