如何在 2 个 HTTP 请求 return 值到商店后触发和 NgRx 操作
How to trigger and NgRx action after 2 HTTP requests return values to the store
我在 2 个不同的数据库中存储了相同的数据类型。
- 在 SQL 数据库 中,我存储了所有食物的大量列表。
- 在 Mongo 数据库上 我正在存储个人的食物数据,这将覆盖提供的默认食物数据。
两种类型的数据都存储在我的 ngrx
商店 ApplicationState
export interface ApplicationState {
serverFoodData: FoodData;
userFoodData: FoodData;
mergedFoodData: FoodData;
}
我需要保留其中每一个的版本,这样我可以在用户添加它们时保存额外的 userFoodData
覆盖,这样我就可以在发生这种情况时重新计算 mergedFoodData
。
因此,我需要检测两个 http
请求何时都已解析到存储并触发操作以计算新的 mergedFoodData
对象。 我该怎么做?
目前我正在 dispatch()
ing 并采取行动从 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))
}
如您所见,我已尝试分派一个操作来合并 2 个 FoodData
对象,但它 dispatch()
ing 具有未实现的值,因为 http
调用尚未完成回应了。
actions.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) { }
}
LoadFoodsEffectService.ts 从 app.component.ts
侦听 dispatch
并调用 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) {
}
}
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() );
}
}
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') };
}
同样,一旦两个 http
调用都已减少到商店中,我如何触发新操作?
在这种情况下,您需要一个动作来触发对服务器的两个请求,然后触发 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)
);
})
我在 2 个不同的数据库中存储了相同的数据类型。
- 在 SQL 数据库 中,我存储了所有食物的大量列表。
- 在 Mongo 数据库上 我正在存储个人的食物数据,这将覆盖提供的默认食物数据。
两种类型的数据都存储在我的 ngrx
商店 ApplicationState
export interface ApplicationState {
serverFoodData: FoodData;
userFoodData: FoodData;
mergedFoodData: FoodData;
}
我需要保留其中每一个的版本,这样我可以在用户添加它们时保存额外的 userFoodData
覆盖,这样我就可以在发生这种情况时重新计算 mergedFoodData
。
因此,我需要检测两个 http
请求何时都已解析到存储并触发操作以计算新的 mergedFoodData
对象。 我该怎么做?
目前我正在 dispatch()
ing 并采取行动从 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))
}
如您所见,我已尝试分派一个操作来合并 2 个 FoodData
对象,但它 dispatch()
ing 具有未实现的值,因为 http
调用尚未完成回应了。
actions.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) { }
}
LoadFoodsEffectService.ts 从 app.component.ts
侦听 dispatch
并调用 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) {
}
}
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() );
}
}
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') };
}
同样,一旦两个 http
调用都已减少到商店中,我如何触发新操作?
在这种情况下,您需要一个动作来触发对服务器的两个请求,然后触发 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)
);
})