如何在 2 个 HTTP 请求将值返回到存储后触发 NgRx 操作

Nat*_*May 3 http typescript ngrx angular

我在两个不同的数据库中存储了等效的数据类型。

  • SQL 数据库中,我存储了所有食物的大量列表。
  • Mongo 数据库中,我存储个人的食物数据,该数据将覆盖提供的默认食物数据。

两种类型的数据都存储在我的ngrx商店中ApplicationState

export interface ApplicationState {
   serverFoodData: FoodData;
   userFoodData: FoodData;
   mergedFoodData: FoodData;
}
Run Code Online (Sandbox Code Playgroud)

我需要保留每个版本的版本,以便userFoodData在用户添加它们时我可以保存额外的覆盖,以便我可以mergedFoodData在发生这种情况时重新计算。

因此,我需要检测两个http请求何时已解析到存储并触发计算新mergedFoodData对象的操作。我怎样才能做到这一点?

目前我正在dispatch()采取行动来加载每个app.component.ts

  constructor(private store: Store<ApplicationState>) {

    this.store.dispatch(new LoadFoodsAction());
    this.store.dispatch(new LoadUserDataAction(1)); // 1 = temporary userID
    // this.foodStates$ = store.select(foodStatesSelector);
    // this.foodStates$.subscribe(foodStates => this.currentFoodStates = foodStates);
    // this.store.dispatch(new BuildMergedFoodDataAction(this.currentFoodStates))
  }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我尝试调度一个操作来合并这两个FoodData对象,但它dispatch()带有未实现的值,因为http调用尚未响应。

动作.ts

// SQL FOODS
export const FOODS_LOADED_ACTION = 'FOODS_LOADED_ACTION';
export const LOAD_FOODS_ACTION = 'LOAD_FOODS_ACTION';


export class FoodsLoadedAction implements Action {
    readonly type = FOODS_LOADED_ACTION;
    constructor(public payload?: AllFoodData) { } // '?' is important
}
export class LoadFoodsAction implements Action {
    readonly type = LOAD_FOODS_ACTION;
    constructor(public payload: number) { }
}


// USER FOODS ACTIONS
export const LOAD_USER_DATA_ACTION = 'LOAD_USER_DATA_ACTION';
export const USER_DATA_LOADED_ACTION = 'USER_DATA_LOADED_ACTION';

export class UserDataLoadedAction implements Action {
    readonly type = USER_DATA_LOADED_ACTION;
    constructor(public payload?: AllUserData) { }
}
export class LoadUserDataAction implements Action {
    readonly type = LOAD_USER_DATA_ACTION;
    constructor(public payload: number) { }
}

// MERGE FOODS ACTION
export const BUILD_MERGED_FOOD_DATA_ACTION = 'BUILD_MERGED_FOOD_DATA_ACTION';

export class BuildMergedFoodDataAction implements Action {
    readonly type = BUILD_MERGED_FOOD_DATA_ACTION;
    constructor(public payload: FoodStates) { }
}
Run Code Online (Sandbox Code Playgroud)

LoadFoodsEffectService.ts监听 fromdispatchapp.component.ts调用http服务

@Injectable()
export class LoadFoodsEffectService {

  @Effect() foods$: Observable<Action> = this.actions$
    .ofType(LOAD_FOODS_ACTION)
    .switchMap( () => this.foodService.loadServerFoods(1) ) // 1 = userID
    .map(allFoodData => new FoodsLoadedAction(allFoodData) );

  constructor(private actions$: Actions, private foodService: FoodService) {
  }
}
Run Code Online (Sandbox Code Playgroud)

从效果服务调用food-service.ts

@Injectable()
export class FoodService {

  constructor(private http: Http) { }

  loadServerFoods(userId: number): Observable<AllFoodData> {
    return this.http.get('/api/foods', commonHttpHeaders(userId)) // see proxy.config.json for the url
      .map( res => res.json() );
  }
}
Run Code Online (Sandbox Code Playgroud)

serverFoodDataReducer.ts然后将响应http添加到Application State

export function serverFoodData(state: ServerFoodState = INITIAL_FOOD_DATA, action: Action): ServerFoodState {
  switch (action.type) {
    case FOODS_LOADED_ACTION:
      return handleFoodsLoadedAction(state, action);
    default:
      return state;
  }
}

export function handleFoodsLoadedAction(state: ServerFoodState, action: FoodsLoadedAction): ServerFoodState {
  return { foods: _.keyBy(action.payload.foods, 'id') };
}
Run Code Online (Sandbox Code Playgroud)

http同样,一旦两个呼叫都减少到商店后,我如何触发新操作?

Ber*_*fer 5

在这种情况下,您将需要一个操作来触发对服务器的两个请求,然后触发 3 个操作。我认为这样的事情应该对你有用:

@Effect()
food$ = this.actions$
.ofType('LoadFood') // This one is to trigger BOTH foods, you would have 
// another action for just the SQL or Mongo data.
.switchMap(action => {
  return Observable.combineLatest(
    service.loadServerFood(),
    service.loadUserFood()
  )
}).switchMap(([serverFood, userFood]) => {
  return Observable.of(
    serverFoodLoadedAction(serverFood),
    userFoodLoadedAction(userFood),
    mergeFoodAction(serverFood, userFood)
  );
})
Run Code Online (Sandbox Code Playgroud)