简体   繁体   中英

How to use async and await in NGRX effect of angular

I am working with NGRX (State Management) in angular 11.

I am showing a tenant list on component load. Using NGRX effect and in effect i am requesting http call through service.

This is my effect

@Injectable()
export class TenantsListEffects {
constructor(private actions$: Actions, private tenantListService: 
TenantAdministrationService) { }


loadTenants$ = createEffect(() => this.actions$.pipe(
ofType(TenantsListActions.TenantsListActionTypes.LoadTenantsLists),

switchMap(
  
  ((action) => this.tenantListService.getAllTenantsUsingGET().pipe(

  map(tenants => { return new TenantsListActions.LoadTenantsListsSuccess({ 
  data: tenants }) }),
    catchError(err => of(new TenantsListActions.LoadTenantsListsFailure({ 
  error: err })))
    )
    )
   ))
   )
  }

This is my tenantList.reducer.ts

    export const tenantsListFeatureKey = 'tenantsListState';


    export interface tenantsListState {
     tenants: DisplayNameToTenantMappingResponse[],
     loading: boolean,
     error: string
    }

     export const initialState: tenantsListState = {
  tenants: [],
  loading: false,
  error: ''
};


export function reducer(state = initialState, action: TenantsListActions): tenantsListState {
  switch (action.type) {
    case TenantsListActionTypes.LoadTenantsLists:
      return {
        ...state,
        loading: true
      }
    case TenantsListActionTypes.LoadTenantsListsSuccess:
      return {
        ...state,
        tenants: action.payload.data,
        loading:false,
        error: null
      }
    case TenantsListActionTypes.LoadTenantsListsFailure:
      return {
        ...state,
        error: action.payload.error,
        loading: false
      }

    default:
      return state;
  }
}

This is my selector

const getTenantsListState = createFeatureSelector<tenantsListState>('tenantsListState');

export const getTenants = createSelector(
    getTenantsListState,
    state => state.tenants
)

export const getError = createSelector(
    getTenantsListState,
    state => state.error
)

This is my service

@Injectable({
providedIn: 'root'
})
export class TenantAdministrationService {
public basePath: string ='';
constructor(private basePathService: BasePathService,private http: 
HttpClient) {
this.basePath = this.basePathService.selectEnv();
}

public 
getAllTenantsUsingGET():Observable<DisplayNameToTenantMappingResponse[]>{
let test =  this.http.get<Array<DisplayNameToTenantMappingResponse>> 
(`${this.basePath}/admin/tenant`);
console.log('get list ', test);

return test
}

The problem is

When i first called the service it retunes nothing and so it didn't store any thing in my ngrx store. But after 2 to 3 second it returns tenant list and stored in the store as a state.

i Tried to make async function to my service call method but it cause error in Effect.

So could some one help me how to handle this....

在此处输入图像描述

It looks like you have things set up right, but I see an extra paren ( after switchMap. Like this it should work.

loadTenants$ = createEffect(() => this.actions$.pipe(
  ofType(TenantsListActions.TenantsListActionTypes.LoadTenantsLists),
  switchMap(action => this.tenantListService.getAllTenantsUsingGET().pipe(
    map(tenants => new TenantsListActions.LoadTenantsListsSuccess({ data: tenants }),
    catchError(err => of(new TenantsListActions.LoadTenantsListsFailure({ 
  error: err })))
  )
);

Keep in mind, your reducer needs to add the entities to state before your store selector will emit them.

const reducer = createReducer(
  initialState,
  on(TenantsListActions.LoadTenantsListsSuccess, (state, { data }) => featureAdapter.setAll(data, {
    ...state,
    isLoading: false,
    error: null,
  })),
  ...
);

Above I'm using an entity adapter to add the entities to state.

I solved the problem i used the state property loading and used it as an observable in my component. `

export interface tenantsListState {
     tenants: DisplayNameToTenantMappingResponse[],
     loading: boolean,
     error: string
    }

`

During the http call this becomes loading = true; and it triggered a spinner which stop the component loading until the http call is return back.

I solved the problem using a switchMap to call an async function, and after that I used a map to process the result from the async function. I'm using Angular 13 and NgRx 13.

My code:

  loadUser$ = createEffect(() => this.actions$.pipe(
    ofType(AuthEvent),
    concatLatestFrom( () => [
      this.store.select(getUid),
      this.store.select(getEmail)
    ]),
    switchMap( ([action, uid, email]) => this.service.loadUser(uid, email)),
    map( user => {
      console.log(user);
      switch (user.level) {
         ....
      }
    }),
    catchError( error => {
      console.error(error);
      return of(UnexpectedError());
    })    
  ));

I'm doing this:

  loadUser$ = createEffect(() => this.actions$.pipe(
    ofType(...),
    concatLatestFrom(...),
    switchMap( () => this.service.anAsyncFuntion()),
    map(...),
    catchError(...)    
  ));

instead of this:

  loadUser$ = createEffect(() => this.actions$.pipe(
    ofType(...),
    concatLatestFrom(...),
    switchMap( () => this.service.anAsyncFuntion()).pipe(
       map(...),
       catchError(...)
    )
  ));

I'm not using pipe to deal with the output from switchMap.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM