Tumeco
Tumeco

Reputation: 115

Dispatch multiple action and wait completion to send next

I'm returning multiple action from one effect, concatMap send action in order but don't wait for completion to send next action. loadDetails call a REST service and update store when he receive loadDetailsSuccess

I want to finish loadDetailsAction before calling HttpResultActions.httpRequestUpdateSuccessful().

How can achieve that? From a different action?

@Effect()
  removeLibelle$ = this.actions$
    .ofType(DetailsActions.DELETE_LIBELLE)
    .map(toPayload)
    .withLatestFrom(this.store$.select(state => state.tree))
    .switchMap(([payload, tree]) => this.libelleService.deleteItem(payload)
      .concatMap(() => {
        return [
         DetailsActions.clear(), //function dispatch action clear
          DetailsActions.loadDetails({ entity: tree.entity,
            dateSearch: tree.search.dateSearch }), //function dispatch GET
          HttpResultActions.httpRequestUpdateSuccessful() //Dispatch action to show modal success
        ];
      }).catch(error => Observable.of(HttpResultActions.httpRequestError(error))));

Upvotes: 5

Views: 3911

Answers (1)

Vamshi
Vamshi

Reputation: 9331

You are doing too many things in single effect. You can liberally break it into multiple effects . Think it this way.

DELETE ---> perform delete ----> DELETE_SUCCESS , DELETE_ERROR

DELETE_SUCCESS ---> clear data ----> DATA_CLEAR_SUCCESS

DATA_CLEAR_SUCCESS ----> load data ----> LOAD_DATA_SUCCESS 

I did the actions in series . You can perform them in parallell also. May be you want to trigger both clear data and load data immediately , then it looks like this :

DELETE ---> perform delete ----> DELETE_SUCCESS , DELETE_ERROR

DELETE_SUCCESS ---> clear data ----> DATA_CLEAR_SUCCESS

DELETE_SUCCESS ----> load data ----> LOAD_DATA_SUCCESS 

Now you can perform model changes in any of these actions. Interesting part is , you may have same model change for get http call or get http call after delete is success. That is the beauty of redux.

Your code looks like this

@Effect()
  removeLibelle$ = this.actions$
    .ofType(DetailsActions.DELETE_LIBELLE)
    .map(toPayload)
    .withLatestFrom(this.store$.select(state => state.tree))
    .switchMap(([payload, tree]) => 
        this.libelleService.deleteItem(payload)
    )// return DELETE_SUCCESS
    .catch() //return DELETE_FAIL

 @Effect()
  removeLibelleDataClear$ = this.actions$
    .ofType(DetailsActions.DELETE_LIBELLE)
        //perform  DetailsActions.clear(),
        //return DATA_CLEAR_SUCCESS action
        // return DATA_CLEAR_ERROR action 

 // If you want to data load in parallell with clear, 
 // you can listen on delete_success . If you want to do 
 // it after data_clear, then listen on data_clear_success 
 @Effect()
  removeLibelleDataClear$ = this.actions$
    .ofType(DetailsActions.DATA_CLEAR_SUCCESS)
        //perform  
        //DetailsActions.loadDetails({ entity: tree.entity,
        //    dateSearch: tree.search.dateSearch })
        // DATA_LOAD_SUCCESS 
        //catch: DATA_LOAD_ERROR

You may wish to immediately notify the user that delete is success. And refresh data . Or you can add different action DELETE_SUCCESS_DATA_LOAD_SUCCESS and inform user that delete is success.

Breaking this way makes testing very very easy, compare this with complex switchmap+concat+three http calls.

Upvotes: 5

Related Questions