2017-01-17 12 views
10

Chciałbym diapatch dwie akcje w jednym efekcie. Obecnie mam zadeklarować dwa efekty, aby osiągnąć w ten sposób:wysyłanie wielu działań w jednym efekcie

// first effect 
    @Effect() action1$ = this.actions$ 
    .ofType(CoreActionTypes.MY_ACTION) 
    .map(res => { 
     return { type: "ACTION_ONE"} 
    }) 
    .catch(() => Observable.of({ 
     type: CoreActionTypes.MY_ACTION_FAILED 
    })); 

    // second effect 
    @Effect() action2$ = this.actions$ 
    .ofType(CoreActionTypes.MY_ACTION) 
    .map(res => { 
     return { type: "ACTION_TWO"} 
    }) 
    .catch(() => Observable.of({ 
     type: CoreActionTypes.MY_ACTION_FAILED 
    })); 

to możliwe, aby mieć jedną akcję, być źródłem dwóch działań poprzez pojedynczy efekt?

+1

FYI, z 'catch' złożonej gdzie jest to w efekcie, jeśli wystąpi błąd, obserwowalne zakończy a twój efekt przestanie działać. Zobacz [tę odpowiedź] (http://stackoverflow.com/a/41685689/6680611). – cartant

Odpowiedz

2

mergeMap Można wybrać dla asynchronicznej lub concatMap do synchronizacji

@Effect() action$ = this.actions$ 
    .ofType(CoreActionTypes.MY_ACTION) 
    .mergeMap(() => Observable.from([{type: "ACTION_ONE"} , {type: "ACTION_TWO"}])) 
    .catch(() => Observable.of({ 
     type: CoreActionTypes.MY_ACTION_FAILED 
    })); 
+0

Głównym problemem związanym z tą odpowiedzią jest problem z wydajnością (który może być akceptowalny), ale także problem spójności, co może być bardzo trudne. Jeśli podzielisz swoje działania i uzyskasz stan znormalizowany, wysłanie 2 działań bez użycia działań wsadowych może doprowadzić do niespójności w sklepie i niektóre selektory Twojej aplikacji mogą zakończyć się błędami. – Maxime

5

Można użyć switchMap i Observable.of.

@Effect({ dispatch: true }) action$ = this.actions$ 
    .ofType(CoreActionTypes.MY_ACTION) 
    .switchMap(() => Observable.of(
     // subscribers will be notified 
     {type: 'ACTION_ONE'} , 
     // subscribers will be notified (again ...) 
     {type: 'ACTION_TWO'} 
    )) 
    .catch(() => Observable.of({ 
     type: CoreActionTypes.MY_ACTION_FAILED 
    })); 

kwestie wydajności:

Zamiast wysyłania wielu działań, które będą spust wszyscy abonenci tyle razy, ile wysyłką, może warto spojrzeć w redux-batched-actions.

Umożliwia to ostrzeżenie subskrybentów tylko wtedy, gdy wszystkie te działania zostały zastosowane do sklepu.

Na przykład:

@Effect({ dispatch: true }) action$ = this.actions$ 
    .ofType(CoreActionTypes.MY_ACTION) 
    // subscribers will be notified only once, no matter how many actions you have 
    // not between every action 
    .map(() => batchActions([ 
     doThing(), 
     doOther() 
    ])) 
    .catch(() => Observable.of({ 
     type: CoreActionTypes.MY_ACTION_FAILED 
    })); 
+1

Dzięki. Jak przetestować wiele zwróconych działań? – Lev

1

można również wykorzystać uruchamiać() i() store.next

zrobić pozwala dołączyć wywołania zwrotnego do zaobserwowania bez wpływu na inne podmioty/wymiana możliwe do zaobserwowania

np.

@Effect() action1$ = this.actions$ 
.ofType(CoreActionTypes.MY_ACTION) 
.do(myaction => this.store.next({type: 'ACTION_ONE'})) 
.switchMap((myaction) => Observable.of(
    {type: 'ACTION_TWO'} 
)) 
.catch(() => Observable.of({ 
    type: CoreActionTypes.MY_ACTION_FAILED 
})); 

(trzeba będzie odniesienie do sklepu w swojej klasie efekty)

+0

Idealny. Dziękuję bardzo Jus. Uczę się tej biblioteki, a twój przykład pomógł mi w synchronizacji z wieloma akcjami –

14
@Effect() loadInitConfig$ = this.actions$ 
    .ofType(layout.ActionTypes.LOAD_INIT_CONFIGURATION) 
    .map<Action, void>(toPayload) 
    .switchMap(() => this.settingsService.loadInitConfiguration() 
     .mergeMap((data:any) => { 
      return [ 
       new layout.LoadInitConfigurationCompleteAction(data.settings), 
       new meetup.LoadInitGeolocationCompleteAction(data.geolocation) 
      ]; 
     }) 
     .catch(error => Observable.of(new layout.LoadInitConfigurationFailAction({ error }))) 
    ); 
Powiązane problemy